最近在写一个数据库访问的中间平台时,使用MySQL JDBC处理一些日期数据,遇到点变态的问题,给大家乐一乐!
首先来看看什么样的日期数据这么蛋疼呢?
DATE 0000-00-00
DATETIME 0000-00-00 00:00:00
TIMESTAMP 0000-00-00 00:00:00
TIME 25:21:22
对于前3种情况,直接用JDBC读取,肯定会报错,报错信息类似这样:
Value '0000-00-00' can not be represented as java.sql.Date
或者
Value '0000-00-00' can not be represented as java.sql.Timestamp
为什么?日期值即使是0,也对应到1970-01-01,这种变态的日期格式,不知道那个奇人想出来的。
对于这样的问题,很多小伙伴想到的第一种办法就是在jdbc url参数上设置一个:zeroDateTimeBehavior=convertToNull
便可以让Java程序不报错了!因为JDBC内部发现是0日期格式,则会转换为null返回。
验证中确实可以解决问题,但是,但是,某个用户的数据库就是写入了这样的一条数据,但是程序确返回了null,用户认为这并不是他想要的数据(例如在做数据迁移时,目标字段不可空,此时就会报错),用户就希望看到的是0000-00-00这样格式的数据。怎么办呢?
首先必须是将参数zeroDateTimeBehavior=convertToNull去掉,否则程序拿到的始终是null,根本不知道数据库的数据是什么。但是这样程序会报错,不论用getString还是getObject都会报错。
经过验证,发现getBytes()不会报错,然后通过得到的bytes[]数组,new String(bytes[])就可以得到一个这样的字符串,并且与数据库内一致。似乎问题解决了?
没有,更蛋疼的问题出现了,当JDBC启用流模式或游标模式时,getBytes()也会报同样的错误,经过验证发现get各种类型都会报错,这尼玛太蛋疼了,没空看源码,据我估计,MySQL JDBC在流模式和游标模式中,对结果集的某些类型转换处理,没有复用普通模式(默认是本能地静态数据)的处理代码导致了这样的问题。
但是对于某些大数据的处理,业务应用中必须启用流模式或游标模式,因此陷入了一个死套--因此我认为这是MySQL JDBC的一个BUG。
但是用户的问题必须要解决,为此,不得不去用一下特殊的处理方式,异常判定,我想你看到这里应该认为这是世界上最土的办法了,呵呵!也就是捕获上面描述的Message信息,若发现则认为是0日期格式来解决,准备提交官方BUG,希望尽快能修复吧。
最后来说说Time类型,MySQL这个蛋疼的Time类型是指时长,而不是指日期上的小时:分钟:秒,因此它的小时数是可以超过24的,但是这样的值让Java来解析就会报错,因此对于MySQL的Time类型处理的时候未了避免问题。通常用getBytes()方式来获取值,然后用new String(byte[])来得到具体值,当然先要判空。