首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

iBatis Date类型时间丢失有关问题

2012-08-21 
iBatis Date类型时间丢失问题初转自http://blog.feihoo.com/2010/11/jdbc-ibatis-datetimes.html在此前,遇

iBatis Date类型时间丢失问题

初转自http://blog.feihoo.com/2010/11/jdbc-ibatis-datetimes.html

在此前,遇到过使用Ibatis操作Oracle时时间精度丢失的问题,昨天又遇到JDBC操作MySQL时间字段的问题,从网上看到各种式样的解释这些问题的博文/帖子,但多是雾里看花,不得要领。

    理解JDBC中的时间类型MySQL与JDBC之间的类型映射Oracle与JDBC之间的类型映射Ibatis是怎么处理日期时间类型的注释参考资料
理解JDBC中的时间类型

java.sql包中包括三个类,Date, Time, 和 Timestamp,分别用来表示日期(无时间信息,eg: YYYY-MM-DD),时间(只处理时间,无日期部分, eg: HH:MM:SS)和时间戳(精确到纳秒级别)。在 它们都继承自java.util.Date。java.sql.Date和java.sql.Time都存有一个时间域,该时间域是精确到秒级别的,但是,他们只处理日期或者时间部分。在MySQL Connector/J(v5.1.13)的实现中可以看到,PrepareStatement#setDate 时会将时间重新format成”yyyy-MM-dd”格式。

因为历史遗留以及各种数据库本身的不同,各种JDBC实现中留下了格式各样的花招, 某些特殊场景下不遵照此情况可能也能工作,但不推荐这样做。

你必须根据你的实际需要来选择不同的类型,通常应该选用精确度与相应的数据库字段类型相比相同或者更高的JDBC类型

除此以外,还可以使用java.uitl.Date类型来处理时间。java.util.Date类型是上面各个类型的父类型,JDBC的API大都可以使用。

除此以外,在JDK1.6之前版本的构造java.sql.{Date|Time|TimeStamp}对象时存在性能问题,尤其是在多线程环境下更严重。这个Bug在这里。其原因是java.util.Date的相关方法调用了TimeZone.getDefaultRef(),而此方法是同步方法注1。

MySQL的JDBC类型映射

DATE java.sql.DateDATETIMEjava.sql.TimestampTIMESTAMP[(M)] java.sql.TimestampTIMEjava.sql.TimeYEAR[(2|4)]If yearIsDateType configuration property is set to false, then
the returned object type is java.sql.Short. If set to true (the
default) then an object of type java.sql.Date (with the date
set to January 1st, at midnight).

MySQL的DATETIME、TIMESTAMP两种字段类型的显著区别在于TIMESTAMP的取值在’1970-01-01 00:00:01′ UTC 和 ‘2038-01-19 03:14:07′ UTC之间。

MySQL在时间处理方面也有一个问题,当Datetimes类型的字段的值为0000-00-00时取值方法会得到下面的异常:

?

此时不论你pojo.Info中的字段类型(或者的javaType属性)是java.util.Date还是java.sql.Date,最终都会丢失数据。实际上,在pojo.Info中的字段类型(或者javaType属性)为java.util.Date时,如果指定jdbcType为DATE或TIME(区分大小写),则将分别得到DateOnlyTypeHandler或TimeOnlyTypeHandler。如果你不指定jdbcType,或者指定一个错误的值,例如datetime,或者xxxx等,都会得到DateTypeHandler(日期时间都会处理)。

如果pojo.Info中的属性类型(或者配置中的javaType属性)是java.sql.Date,则选择处理handler类时不会使用jdbcType,而是根据属性类型得到SqlDateTypeHandler(只包含日期)。

在Ibatis的手册中,指出来jdbcType一般情况下是不用于判断处理方式的注3。大部分情况下是依据javaType或者pojo属性类型来判断处理方式,在少部分无法根据pojo属性类型判断的情况下才使用。如果你用java.util.Date对应到MySQL,则就是这种少数情况之一。因为MySQL可以将多个数据库字段类型映射到java.util.Date,所以需要指定是DATE还是TIME(必须是大写),如果不指定则默认是完整的日期时间(此时按JDBC的timestamp操作)。

针对ibatis对时间的处理,我写了个测试,点此看测试代码。

对于Ibatis操作Date/Time/DateTime,总结如下:

将pojo的属性类型设置为java.sql.Date(或java.sql.Time, java.sql.Timestamp),此时会严格遵循这三种类型的语义。但此方法因存在前文中提到的性能问题,在JDK1.6以前的JDK版本中能少使用就少使用。如果你想在pojo中使用java.util.Date, 则要注意:完整的日期时间,要确保jdbcType为空,或为DATE,TIME以外的值只需要时间,要指定jdbcType=”TIME”只需要日期,要指定jdbcType=”DATE”

补充一下:当我按照本文所说修改以后,发现仍然存在这个问题,经过仔细排叉,发现我在保存数据的时候,参数类型为java.sql.Date我又看了一下我的insert片断语句为:

?我试着将代码修改为:

?此时再查看debug日志,发现参数类型变为 java.sql.Timestamp问题到此解决,看来不光是resultMap,在insert与update等语句中也要修改。Ps:我的配置文件是由ibator生成

热点排行