実行しようとすると例外が発生します(以下を参照)
resultset.getString("add_date");
としてではなく、文字列として値を取得しようとしているにもかかわらず、0000-00-00 00:00:00(DATETIMEの準ヌル値)のDATETIME値を含むMySQLデータベースへのJDBC接続の場合オブジェクト。
私はこれを回避するために
SELECT CAST(add_date AS CHAR) as add_date
動作しますが、ばかげているようです...これを行うより良い方法はありますか?
私のポイントは、生のDATETIME文字列だけが必要なので、自分で解析できることですas。
note:ここに0000が入ります:(from http://dev.mysql.com/doc/refman/5.0/en /datetime.html )
無効なDATETIME、DATE、またはTIMESTAMP値は、適切なタイプの「ゼロ」値(「0000-00-00 00:00:00」または「0000-00-00」)に変換されます。
特定の例外はこれです:
SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
SQLState: S1009
VendorError: 0
Java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.Java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.Java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.Java:926)
at com.mysql.jdbc.ResultSetImpl.getTimestampFromString(ResultSetImpl.Java:6343)
at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.Java:5670)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.Java:5491)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.Java:5531)
同じ問題を解決しようとして、私はこれに出くわしました。私が作業しているインストールではJBOSSとHibernateを使用しているため、これを別の方法で行う必要がありました。基本的なケースでは、この 構成プロパティページ に従ってzeroDateTimeBehavior=convertToNull
を接続URIに追加できるはずです。
休止状態の設定にそのパラメーターを配置することについて言及している他の提案を土地全体で見つけました:
hibernate.cfg.xml:
<property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
hibernate.properties:
hibernate.connection.zeroDateTimeBehavior=convertToNull
しかし、JBOSSのmysql-ds.xmlファイルに次のように配置する必要がありました。
<connection-property name="zeroDateTimeBehavior">convertToNull</connection-property>
これが誰かを助けることを願っています。 :)
別の答えとして、このJDBC URLをデータソース構成で直接使用できます。
jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull
編集:
すべてゼロのコンポーネントを持つ日付時刻(0000-00-00 ...)—これらの値は、Javaで確実に表すことができません。 Connector/J 3.0.xは、ResultSetから読み取られるときに、常にNULLに変換しました。
これらの値に遭遇すると、Connector/J 3.1はデフォルトで例外をスローします。これは、JDBCおよびSQL標準に従って最も正しい動作であるためです。この動作は、zeroDateTimeBehavior構成プロパティを使用して変更できます。許容値は次のとおりです。
- exception(デフォルト)、S1009のSQLStateでSQLExceptionをスローします。
- convertToNull。日付の代わりにNULLを返します。
- round。日付を最も近い0001-01-01に丸めます。
更新:Alexanderは、その機能のmysql-connector-5.1.15に影響するバグを報告しました。 公式Webサイトの変更ログ を参照してください。
私のポイントは、生のDATETIME文字列が欲しいだけなので、そのまま自分で解析できるということです。
そのため、「回避策」は回避策ではなく、実際にデータベースからコードに値を取得する唯一の方法だと思います。
SELECT CAST(add_date AS CHAR) as add_date
ちなみに、MySQLのドキュメントからのいくつかのメモ:
MySQL 無効なデータの制約 :
MySQL 5.0.2より前では、MySQLは違法または不適切なデータ値を許容しており、データ入力の正当な値に強制します。 MySQL 5.0.2以降では、これがデフォルトの動作のままですが、サーバーのSQLモードを変更して、サーバーがそれらを拒否し、発生したステートメントを中止するように、より伝統的な不良値の処理を選択できます。
[..]
NULL値を受け取らない列にNULLを保存しようとすると、単一行のINSERTステートメントでエラーが発生します。複数行のINSERTステートメントまたはINSERT INTO ... SELECTステートメントの場合、MySQLサーバーは列データ型の暗黙のデフォルト値を保存します。
MySQL 5.x 日付と時刻のタイプ :
MySQLでは、「ダミー日付」として「0000-00-00」を保存することもできます(NO_ZERO_DATE SQLモードを使用していない場合)。これは、場合によっては、NULL値を使用するよりも便利です(使用するデータとインデックススペースが少なくなります)。
[..]
デフォルトでは、MySQLは、範囲外のデータ型または時刻型の値を検出した場合(このセクションの冒頭で説明したように)、その型に対して無効です。値をその型の「ゼロ」値に変換します。
DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime
これを使用してエラーを回避してください。文字列形式で日付を返し、文字列として取得できます。
resultset.getString("dtime");
これは実際には機能しません。 getStringを呼び出しても。内部的には、mysqlはまだ最初にそれを日付に変換しようとします。
com.mysql.jdbc.ResultSetImpl.getDateFromString(ResultSetImpl.Java:2270)で
〜[mysql-connector-Java-5.1.15.jar:na] at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.Java:5743)
〜[mysql-connector-Java-5.1.15.jar:na] at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.Java:5576)
〜[mysql-connector-Java-5.1.15.jar:na]
行を追加した後:
<property
name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
hibernate.connection.zeroDateTimeBehavior=convertToNull
<connection-property
name="zeroDateTimeBehavior">convertToNull</connection-property>
エラーのままです:
Illegal DATETIME, DATE, or TIMESTAMP values are converted to the “zero” value of the appropriate type ('0000-00-00 00:00:00' or '0000-00-00').
行を見つける:
1) resultSet.getTime("time"); // time = 00:00:00
2) resultSet.getTimestamp("timestamp"); // timestamp = 00000000000000
3) resultSet.getDate("date"); // date = 0000-00-00 00:00:00
それぞれ次の行に置き換えます。
1) Time.valueOf(resultSet.getString("time"));
2) Timestamp.valueOf(resultSet.getString("timestamp"));
3) Date.valueOf(resultSet.getString("date"));
この問題に取り組み、上記の「convertToNull」ソリューションを実装しました。ローカルのMySqlインスタンスで動作しました。しかし、Play/ScalaアプリをHerokuにデプロイすると、機能しなくなりました。 Herokuは、ユーザーに提供するDB URLにいくつかの引数を連結します。また、Herokuは「?」の連結を使用するため、このソリューションも連結します。独自の引数セットの前では、機能しません。しかし、同じように機能する別のソリューションを見つけました。
SET sql_mode = 'NO_ZERO_DATE';
これをテーブルの説明に入れて、「0000-00-00 00:00:00」という問題がJava.sql.Timestampとして表せないという問題を解決しました
Null値を表すためにnullを使用することをお勧めします。
あなたが得る例外は何ですか?
ところで:
0または0000と呼ばれる年はありません(一部の日付では今年が許可されます)
また、年の0月または月の0日はありません。 (問題の原因である可能性があります)
「00-00 -....」が有効な日付ではないという問題を解決した後、SQL値の定義を変更して、NULL値を許可するように「NULL」式を追加しました。
SELECT "-- Tabla item_pedido";
CREATE TABLE item_pedido (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
id_pedido INTEGER,
id_item_carta INTEGER,
observacion VARCHAR(64),
fecha_estimada TIMESTAMP,
fecha_entrega TIMESTAMP NULL, // HERE IS!!.. NULL = DELIVERY DATE NOT SET YET
CONSTRAINT fk_item_pedido_id_pedido FOREIGN KEY (id_pedido)
REFERENCES pedido(id),...
次に、NULL値を挿入できるようにする必要があります。つまり、「そのタイムスタンプをまだ登録していません」ということです。
SELECT "++ INSERT item_pedido";
INSERT INTO item_pedido VALUES
(01, 01, 01, 'Ninguna', ADDDATE(@HOY, INTERVAL 5 MINUTE), NULL),
(02, 01, 02, 'Ninguna', ADDDATE(@HOY, INTERVAL 3 MINUTE), NULL),...
テーブルは次のように見えます。
mysql> select * from item_pedido;
+----+-----------+---------------+-------------+---------------------+---------------------+
| id | id_pedido | id_item_carta | observacion | fecha_estimada | fecha_entrega |
+----+-----------+---------------+-------------+---------------------+---------------------+
| 1 | 1 | 1 | Ninguna | 2013-05-19 15:09:48 | NULL |
| 2 | 1 | 2 | Ninguna | 2013-05-19 15:07:48 | NULL |
| 3 | 1 | 3 | Ninguna | 2013-05-19 15:24:48 | NULL |
| 4 | 1 | 6 | Ninguna | 2013-05-19 15:06:48 | NULL |
| 5 | 2 | 4 | Suave | 2013-05-19 15:07:48 | 2013-05-19 15:09:48 |
| 6 | 2 | 5 | Seco | 2013-05-19 15:07:48 | 2013-05-19 15:12:48 |
| 7 | 3 | 5 | Con Mayo | 2013-05-19 14:54:48 | NULL |
| 8 | 3 | 6 | Bilz | 2013-05-19 14:57:48 | NULL |
+----+-----------+---------------+-------------+---------------------+---------------------+
8 rows in set (0.00 sec)
最後に:JPAの動作:
@Stateless
@LocalBean
public class PedidosServices {
@PersistenceContext(unitName="vagonpubPU")
private EntityManager em;
private Logger log = Logger.getLogger(PedidosServices.class.getName());
@SuppressWarnings("unchecked")
public List<ItemPedido> obtenerPedidosRetrasados() {
log.info("Obteniendo listado de pedidos retrasados");
Query qry = em.createQuery("SELECT ip FROM ItemPedido ip, Pedido p WHERE" +
" ip.fechaEntrega=NULL" +
" AND ip.idPedido=p.id" +
" AND ip.fechaEstimada < :arg3" +
" AND (p.idTipoEstado=:arg0 OR p.idTipoEstado=:arg1 OR p.idTipoEstado=:arg2)");
qry.setParameter("arg0", Tipo.ESTADO_BOUCHER_ESPERA_PAGO);
qry.setParameter("arg1", Tipo.ESTADO_BOUCHER_EN_SERVICIO);
qry.setParameter("arg2", Tipo.ESTADO_BOUCHER_RECIBIDO);
qry.setParameter("arg3", new Date());
return qry.getResultList();
}
ついにそのすべての仕事。それがお役に立てば幸いです。
他の回答に追加するには:0000-00-00
文字列が必要な場合は、noDatetimeStringSync=true
を使用できます(タイムゾーン変換を犠牲にするという警告があります)。
MySQLの公式バグ: https://bugs.mysql.com/bug.php?id=47108 。
また、履歴については、JDBCは0000-00-00
日付に対してNULL
を返していましたが、デフォルトでは例外を返します。 ソース
jdbc urlを追加できます
?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
これを使用して、sqlが '0000-00-00 00:00:00'をヌル値として変換します。
例えば:
jdbc:mysql:<Host-name>/<db-name>?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8