在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实例中工作。 但是当我将我的Play / 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-00
date返回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