在JDBC中处理DATETIME的值0000-00-00 00:00:00

如果我尝试做,我会得到一个exception(见下文)

resultset.getString("add_date"); 

对于包含DATETIME值为0000-00-00 00:00:00(DATETIME的准空值)的MySQL数据库的JDBC连接,尽pipe我只是试图以stringforms获取该值,而不是目的。

我这样做了

 SELECT CAST(add_date AS CHAR) as add_date 

哪个工作,但似乎很傻…有没有更好的方法来做到这一点?

我的意思是,我只想要原始的DATETIMEstring,所以我可以自己parsing它。

注意:这里是0000进来的地方:(来自http://dev.mysql.com/doc/refman/5.0/en/datetime.html )

非法的DATETIME,DATE或TIMESTAMP值将转换为相应types(“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,所以我必须以不同的方式做到这一点。 对于基本情况,您应该能够根据此configuration属性页面将zeroDateTimeBehavior=convertToNull添加到连接URI。

我发现了其他的build议,把这个参数放在你的hibernateconfiguration中:

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> 

希望这有助于某人。 🙂

另一个答案,你可以直接在你的数据源configuration中使用这个JDBC URL:

 jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull 

编辑:

来源: MySQL手册

具有全零组件的date时间(0000-00-00 …) – 这些值在Java中不能可靠地表示。 Connector / J 3.0.x在从ResultSet读取时始终将它们转换为NULL。

遇到这些值时,Connector / J 3.1默认会引发exception,因为这是根据JDBC和SQL标准最正确的行为。 这个行为可以使用zeroDateTimeBehaviorconfiguration属性进行修改。 允许的值是:

  • exception (缺省值),它引发SQLException与S1009的SQLState。
  • convertToNull ,它返回NULL而不是date。
  • 将date四舍五入到最接近的最接近的值0001-01-01。

更新:Alexander报告了一个影响mysql-connector-5.1.15的bug。 请参阅官方网站上的CHANGELOGS 。

我的意思是,我只想要原始的DATETIMEstring,所以我可以自己parsing它。

这使我认为你的“解决方法”不是一个解决方法,但实际上是从数据库中获取值到你的代码的唯一方法:

 SELECT CAST(add_date AS CHAR) as add_date 

顺便提一下,MySQL文档中有更多的注释:

无效数据上的 MySQL 约束 :

在MySQL 5.0.2之前,MySQL会宽恕非法或不正确的数据值,并将其强制为合法的数据input值。 在MySQL 5.0.2及更高版本中,这仍然是默认行为,但您可以更改服务器SQL模式以select更为传统的错误值处理方式,以便服务器拒绝它们并中止它们出现的语句。

[..]

如果您尝试将NULL存储到不包含NULL值的列中,则对于单行INSERT语句会发生错误。 对于多行INSERT语句或INSERT INTO … SELECT语句,MySQL服务器存储列数据types的隐式默认值。

MySQL 5.x date和时间types :

MySQL还允许你将'0000-00-00'作为“假date”(如果你不使用NO_ZERO_DATE SQL模式)。 这在某些情况下比使用NULL值更方便(并且使用更less的数据和索引空间)。

[..]

默认情况下,当MySQL遇到一个date或时间types的值超出范围或其他types的非法(如本节开头所述)时,它会将该值转换为该types的“零”值。

 DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime 

使用这个来避免错误。 它返回string格式的date,然后你可以得到它作为一个string。

 resultset.getString("dtime"); 

这实际上不起作用。 即使你调用getString。 内部mysql仍然会尝试将其转换为第一个date。

在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的连接器的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 

分别replace为以下几行:

 1) Time.valueOf(resultSet.getString("time")); 2) Timestamp.valueOf(resultSet.getString("timestamp")); 3) Date.valueOf(resultSet.getString("date")); 

我摔跤这个问题,并实施了上面讨论的“convertToNull”解决scheme。 它在我的本地MySql实例中工作。 但是当我将我的Pl​​ay / Scala应用程序部署到Heroku时,它不再起作用。 Heroku还将几个参数连接到它们提供给用户的数据库URL,而这个解决scheme由于Heroku使用“?”连接, 在他们自己的一套参数之前,将不会工作。 不过,我发现了一个不同的解决scheme似乎同样工作。

SET sql_mode ='NO_ZERO_DATE';

我把这个在我的表格描述,它解决了'0000-00-00 00:00:00'的问题不能被表示为java.sql.Timestamp

我build议你使用null来表示一个空值。

你得到的例外是什么?

BTW:

没有一年被称为0或0000.(尽pipe今年有些date允许)

而且一年的0个月或0个月中都没有。 (这可能是你的问题的原因)

我解决了考虑'00 -00 -….'不是有效date的问题,然后,我改变了我的SQL列定义,添加“NULL”expression式以允许空值:

 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(); } 

最后所有的工作。 我希望能帮到你。

要添加到其他答案:如果你想要的string,你可以使用noDatetimeStringSync=true (牺牲时区转换的警告)。

官方的MySQL错误: https : //bugs.mysql.com/bug.php?id = 47108 。

而且,对于历史logging,JDBC用于在0000-00-00date返回NULL ,但现在默认返回一个exception。 资源

你可以追加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