读书人

java Date(util.Date/sql.Date/sql.Ti

发布时间: 2012-12-21 12:03:49 作者: rapoo

java Date(util.Date/sql.Date/sql.Timestamp/sql.Time) & Oracle DATE Type 时分秒 精度问题
遇到的问题描述:
数据库为Oracle,其jdbc驱动为ojdbc14.jar。打算用Hibernate原生SQL通过setResultTransformer()的方式将查询结果赋给不被Hibernate管理的bean:

结果发现:返回的FidsDepfDto list中所有FidsDepfDto对象的时间字段sdt/estDate/actDate都丢失了时分秒精度。
如果使用的是HQL(或还是原生sql,只不过使用addEntity(Class clazz)的方式(这个方法接受的参数clazz应是被hibernate管理的持久化bean,否则会抛异常)),则避免这种精度丢失的方式有:
1 XML元数据的方式配置Hibernate: 将返回日期类型(且想保留时分秒)的列在XML配置文件中指明其type为Timestamp或java.util.Date;
2 注解方式配置Hibernate:在日期类型的get方法上使用@Temporal注解:

2 原生sql语句中使用oracle的to_char()将Oracle内置数据类型DATE转换为varchar后在bean中用String类型接收它。
3 其他几个牵动比较大的解决办法(具体原因见下文论述):在使用Oracle 9.2 - 10.2 jdbc驱动的时候,数据库类型别用DATE,而用TIMESTAMP;设置数据连接属性V8Compatible为true;变更oracle驱动,使用11g的jdbc驱动。

造成时分秒精度丢失的根本原因是什么那?是Oracle 驱动的问题!
在Oracle9.2之后,引入了内置数据类型TIMESTAMP。之所以引入它,是因为内置数据类型DATE的最小单位为秒;DATE的主要问题是它粒度不能足够区别出两个事件哪个先发生。9.2版本后ORACLE在DATE数据类型上扩展出来了TIMESTAMP数据类型,它包括了所有DATE数据类型的年月日时分秒的信息,而且包括了小数秒(纳秒Nanoseconds级的)的信息。如果你想把DATE类型转换成TIMESTAMP类型,就使用CAST函数。
也正是从oracle 9.2开始,内置数据类型DATE和TIMESTAMP在使用9i的JDBC驱动做查询时,DATE被映射为java.sql.Date,TIMESTAMP被映射为java.sql.Timestamp。
幸运的是,从Oracle11开始,其JDBC驱动程序又重新开始回归为将内置类型DATE映射为java.sql.Timestamp(正如9.2之前的那样)。
综上,时分秒精度的丢失与hibernate无关,是oracle jdbc驱动的问题。最好的解决办法就是:换驱动。经测试,将最开始使用的10g的驱动ojdbc14.jar换为11g的驱动ojdbc5.jar后,时分秒精度丢失的问题成功解决!

英文原文:
http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_00
Oracle JDBC 11.1 fixes this problem. Beginning with this release the driver maps SQL DATE columns to java.sql.Timestamp by default. There is no need to set V8Compatible to get the correct mapping. V8Compatible is strongly deprecated. You should not use it at all. If you do set it to true it won't hurt anything, but you should stop using it.

Although it was rarely used that way, V8Compatible existed not to fix the DATE to Date issue but to support compatibility with 8i databases. 8i (and older) databases did not support the TIMESTAMP type. Setting V8Compatible not only caused SQL DATE to be mapped to Timestamp when read from the database, it also caused all Timestamps to be converted to SQL DATE when written to the database. Since 8i is desupported, the 11.1 JDBC drivers do not support this compatibility mode. For this reason V8Compatible is desupported.

As mentioned above, the 11.1 drivers by default convert SQL DATE to Timestamp when reading from the database. This always was the right thing to do and the change in 9i was a mistake. The 11.1 drivers have reverted to the correct behavior. Even if you didn't set V8Compatible in your application you shouldn't see any difference in behavior in most cases. You may notice a difference if you use getObject to read a DATE column. The result will be a Timestamp rather than a Date. Since Timestamp is a subclass of Date this generally isn't a problem. Where you might notice a difference is if you relied on the conversion from DATE to Date to truncate the time component or if you do toString on the value. Otherwise the change should be transparent.

If for some reason your app is very sensitive to this change and you simply must have the 9i-10g behavior, there is a connection property you can set. Set mapDateToTimestamp to false and the driver will revert to the default 9i-10g behavior and map DATE to Date.



oracle 9/10的jdbc驱动将内置数据类型DATE映射为java.sql.Date,为什么会造成时分秒精度的丢失那?
答:java.sql.Date can not hold time,but java.util.Date can。
JDK中的说法(下贴三楼):
http://stackoverflow.com/questions/383783/oracle-sql-date-conversion-problem-using-ibatis-via-java-jdbc引用To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
java.sql.Date is not a real date:
http://www.thunderguy.com/semicolon/2003/08/14/java-sql-date-is-not-a-real-date/引用java.sql.Date stores only date information, not times. Simply converting a java.util.Date into a java.sql.Date will silently set the time to midnight. So, to store date/times to be manipulated as java.util.Date objects


Native Query的自定义转换器:
http://www.cnblogs.com/highriver/archive/2011/03/03.html

读书人网 >SQL Server

热点推荐