今天在使用 Mysql 中的一个 datetime 字段时碰到了一个 Cause: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp 异常,之前使用都没有问题,今天突然出现故障。所以我就仔细查看了一下代码,看看最近是否有人改动。通过最终的搜索排查,我把整个过程分享给大家!
根据异常信息,我翻译了一下,大概意思是说,'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 表示不了,所以就抛出了这个异常。
完整的异常信息如下:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'audit_time' from result set. Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'audit_time' from result set. Cause: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy127.selectOne(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:166)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:82)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy134.findOrderInfo(Unknown Source)
那么知道这个异常产生的原因后,该如何解决呢?
根据 stackoverflow 上一部分人的回答,我得出可以使用下面的方式连接数据库来解决:
jdbc:mysql://www.xttblog.com:3306/xttblog?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 中对日期类型的处理方法。
首先 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 类型。
参考资料
- 3.3.3 Upgrading from MySQL Connector/J 3.0 to 3.1
- '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp error
: » Cause: java.sql.SQLException: Value ‘0000-00-00 00:00:00’ can not be represented as java.sql.Timestamp
原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/251843.html