您的当前位置:首 页 >> 信息中心

00���������������,已解决:java.sql.SQLException: Value ‘0000-00-00 00:00:00‘ can not be represented as java.sql.Timestamp

发布日期:2022-01-18 18:15:13 作者: 点击:

在这里插入图片描述

一、问题 一大早到公司 Mysql 中的一个 datetime 字段时碰到了一个 Cause: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp 异常之前使用都没有问题,本地也是没有问题。今天要部署上线就是不行。通过最终的搜索排查,我把整个过程分享给大家! java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestampat com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.ResultSetRow.getTimestampFast(ResultSetRow.java:937) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.ByteArrayRow.getTimestampFast(ByteArrayRow.java:130) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.ResultSetImpl.getTimestampInternal(ResultSetImpl.java:5921) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.ResultSetImpl.getTimestamp(ResultSetImpl.java:5591) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.mysql.jdbc.ResultSetImpl.getTimestamp(ResultSetImpl.java:5620) ~[mysql-connector-java-5.1.46.jar!/:5.1.46]at com.zaxxer.hikari.pool.HikariProxyResultSet.getTimestamp(HikariProxyResultSet.java) ~[HikariCP-2.7.9.jar!/:na]at org.hibernate.type.descriptor.sql.TimestampTypeDescriptor$2.doExtract(TimestampTypeDescriptor.java:84) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:261) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:247) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:333) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2868) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1747) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1673) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.getRow(Loader.java:1562) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:732) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.processResultSet(Loader.java:991) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.doQuery(Loader.java:949) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.doList(Loader.java:2692) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.doList(Loader.java:2675) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2507) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.Loader.list(Loader.java:2502) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:502) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:392) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:216) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1490) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]at ...省略 二、解决

根据异常信息,我翻译了一下,大概意思是说,‘0000-00-00 00:00:00’ 这个时间不能用 Java 来表示。虽然数据库中可以存放这个值,但是 Java 中的时间都是从 1970 年开始的。格林威治时间 1970年01月01日00时00分00秒(UTC+8北京时间1970年01月01日08时00分00秒),所以你这个 ‘0000-00-00 00:00:00’ 的时间,Java 表示不了,所以就抛出了这个异常。

数据连接处理

那么知道这个异常产生的原因后,该如何解决呢?

jdbc:mysql://www.teddylife.com:3306/test?zeroDateTimeBehavior=convertToNull

MySQL 的官方资料对 zeroDateTimeBehavior 属性做出了详细的解释

设置 zeroDateTimeBehavior 属性,当遇到 DATETIME 值完全由 0 组成时,最终的有效值可以设置为,异常(exception),一个近似值(round),或将这个值转换为 null(convertToNull)。默认情况为 exception,设置这个属性会抛出一个 SQLException 异常,也就是文章开头所说到的异常。其 SQLSate 码为 S1009。这个状态码在写存储过程处理异常时也可以用到。convertToNull,返回 null 来替代 0000-00-00 这样的日期。round,将日期转换为 0001-01-01。因此,出现 0000-00-00 属于一个无效日期,用 convertToNull 属性即可。 Java 中日期 能表示日期的提供了 4 个类,分别是:java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp。 它们的继承关系如下 java.lang.Object....|__java.util.Date..........|__java.sql.Date/java.sql.Timestamp /java.sql.Time....|__java.security.Timestamp* java.util.Date 日期格式为:年月日时分秒 * java.sql.Date 日期格式为:年月日[只存储日期数据不存储时间数据] * java.sql.Time 日期格式为:时分秒 * java.sql.Timestamp 日期格式为:年月日时分秒纳秒(毫微秒)

java.util.Date 这个类是 java.sql.Date, java.sql.Time, java.slq.Timestamp 这三个类的父类。这三个类对 java.util.Date 类进行了包装。

java.sql.Date 类屏蔽了 java.util.Date 类的时间有关的方法(形如:hh:mm:ss),因此,不可以通过这个类访问时间有关的信息,比如,如果你通过 sqlDate.getHour() 方法去访问小时信息,此方法会抛出一个IllegalArgumentException异常。这是因为 java.sql.Date 在继承 java.util.Date 类的时候对父类进行了重写,禁用了时间访问的方法。之所以这么处理,是为了和数据库的Date数据类型相匹配,数据库的Date数据类行只是保存日期有关的字段。

Java.sql.Time 类屏蔽了 java.util.Date 的日期有关的字段(形如:yyyy-MM-dd),因此,不能通过这个类访问日期有关的信息,比如:如果你通过 sqlTime.getYear() 方法去获取年有关的信息,此方法会抛出一个 IllegalArgumentException 异常。这是因为 java.sql.Time 在继承 java.util.Date 类的时候对父类进行了重写,禁用了日期访问的方法。之所以这么处理,是为了和数据库的 Time 数据类型相匹配,数据库的Time数据类行只是保存时间有关的字段。

Java.sql.Timestamp 字段则对 java.util.Date 这个类进行了扩充,它在 java.util.Date 类的基础上增加了毫秒的时间访问控制,因此,你可以通过 getNanos()方法去获取时间的毫微秒数(注意此处获取的时间是以毫微秒为单位的,1秒等于十亿毫微秒),同样的,这也是为了和数据库中的Timestamp数据类型进行匹配。

理清了上述四个类的关系,那么 java.util.Date 和 java.util.Calendar 类有什么关系呢?

Java.util.Calendar 类是 java.util.Date 类的一个更加深入,更加全面的替代。Java.util.Calendar 类支持 java.util.Date 的所有功能,此外,Calendar 还引入了多语言,多区域的特性,可以根据需要获取不同区域,不同时区的时间,Calendar 还增加了比 Date 更加方便和快捷的许多操作,如获取一年当中的第几个星期,各个月的天数等便捷的方法。

java.util.Calendar 区别与 java.util.Date 的几个地方也需要注意一下:首先,Calendar 增加了毫秒的时间段,通过它可以获取时间点的毫秒值,而 java.util.Date 只是精确到秒。其次,Calendar 过去年的时候是当前年份比如:2010,而 Date 获取年份的时获取到的是当前年份-1900的一个值(2010-1900=110,因此,你调用 getYear 后过去的值就是110)。最后 Calendar 是一个抽象类,之所以能够实例化,是因为此处的 Calendar 充当了一个类似于工厂的作用,在 getInstance 方法中实例化了 Calendar 子类 GregorianCalendar,并把它返回给用户使用。

针对不同的数据库选用不同的日期类型 。例如:Oracle的Date类型,只需要年月日,选择使用java.sql.Date类型;MySQL 和 Sqlserver 数据库的 DateTime 类型,需要年月日时分秒,选择 java.sql.Timestamp 类型。

😁 作者:Teddy (公众号:鸡仓故事汇) ok!到这里就大功告成,小编(Teddy)在这里先感谢大家的到来。 虽然不是太详细,小编已经很努力,给小编来个一键三连(点赞,关注,收藏),小编会越来越努力。。。