在JDBC中处理DATETIME values 0000-00-00 00:00:00

Jas*_*n S 83 java sql date jdbc

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

resultset.getString("add_date");
Run Code Online (Sandbox Code Playgroud)

对于包含DATETIME值为00:00:00(DATETIME的准空值)的MySQL数据库的JDBC连接,即使我只是想将值作为字符串,而不是宾语.

我这样做了

SELECT CAST(add_date AS CHAR) as add_date
Run Code Online (Sandbox Code Playgroud)

哪个有效,但看起来很傻......有更好的方法吗?

我的意思是,我只是想生DATETIME字符串,所以我可以解析它自己为是.

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

非法DATETIME,DATE或TIMESTAMP值将转换为相应类型的"零"值('0000-00-0000: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)
Run Code Online (Sandbox Code Playgroud)

Bri*_*zel 121

替代答案,您可以直接在数据源配置中使用此JDBC URL:

jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull
Run Code Online (Sandbox Code Playgroud)

编辑:

来源:MySQL手册

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

默认情况下,遇到这些值时,Connector/J 3.1会抛出异常,因为根据JDBC和SQL标准,这是最正确的行为.可以使用zeroDateTimeBehavior配置属性修改此行为.允许的值是:

  • exception(缺省值),抛出SQLException,SQLState为S1009.
  • convertToNull,返回NULL而不是日期.
  • round,将日期入到最接近的值0001-01-01.

更新:Alexander在该功能上报告了一个影响mysql-connector-5.1.15的错误.请参阅官方网站上的CHANGELOGS.


sar*_*ont 82

我偶然发现了这个问题,试图解决同样的问题.我正在使用的安装使用JBOSS和Hibernate,所以我必须采用不同的方式.对于基本情况,您应该能够zeroDateTimeBehavior=convertToNull根据此配置属性页面添加到您的连接URI .

我在整个土地上找到了其他建议,指的是将该参数放入你的hibernate配置中:

hibernate.cfg.xml中:

<property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
Run Code Online (Sandbox Code Playgroud)

hibernate.properties中:

hibernate.connection.zeroDateTimeBehavior=convertToNull
Run Code Online (Sandbox Code Playgroud)

但我不得不把它放在我的mysql-ds.xml文件中,用于JBOSS:

<connection-property name="zeroDateTimeBehavior">convertToNull</connection-property>
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.:)


Arj*_*jan 11

我的观点是我只想要原始的DATETIME字符串,所以我可以自己解析它.

这让我觉得你的"解决方法"不是一种解决方法,但实际上是从数据库中获取代码的唯一方法:

SELECT CAST(add_date AS CHAR) as add_date
Run Code Online (Sandbox Code Playgroud)

顺便提一下,MySQL文档中还有一些注释:

MySQL 对无效数据的约束:

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

[..]

如果尝试将NULL存储到不接受NULL值的列中,则单行INSERT语句会发生错误.对于多行INSERT语句或INSERT INTO ... SELECT语句,MySQL Server存储列数据类型的隐式默认值.

MySQL 5.x 日期和时间类型:

MySQL还允许您将"0000-00-00"存储为"虚拟日期"(如果您没有使用NO_ZERO_DATE SQL模式).在某些情况下,这比使用NULL值更方便(并且使用更少的数据和索引空间).

[..]

默认情况下,当MySQL遇到超出范围的日期或时间类型的值或者该类型非法时(如本节开头所述),它会将该值转换为该类型的"零"值.


小智 6

DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime
Run Code Online (Sandbox Code Playgroud)

用它来避免错误.它以字符串格式返回日期,然后您可以将其作为字符串.

resultset.getString("dtime");
Run Code Online (Sandbox Code Playgroud)

这实际上不起作用.即使你调用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的连接器的Java-5.1.15.jar:NA]


小智 5

如果,在添加行之后:

<property
name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>

hibernate.connection.zeroDateTimeBehavior=convertToNull

<connection-property
name="zeroDateTimeBehavior">convertToNull</connection-property>
Run Code Online (Sandbox Code Playgroud)

仍然是一个错误:

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').
Run Code Online (Sandbox Code Playgroud)

找到行:

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
Run Code Online (Sandbox Code Playgroud)

分别替换为以下行:

1) Time.valueOf(resultSet.getString("time"));
2) Timestamp.valueOf(resultSet.getString("timestamp"));
3) Date.valueOf(resultSet.getString("date"));
Run Code Online (Sandbox Code Playgroud)


小智 5

我解决了这个问题并实现了上面讨论的'convertToNull'解决方案.它在我的本地MySql实例中工作.但是,当我将Play/Scala应用程序部署到Heroku时,它不再有效.Heroku还将几个args连接到他们为用户提供的DB URL,这个解决方案,因为Heroku使用了串联"?" 在他们自己的一套args之前,将无法正常工作.然而,我找到了一个似乎同样有效的不同解决方案.

SET sql_mode ='NO_ZERO_DATE';

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