当前位置:  开发笔记 > 编程语言 > 正文

通过Java JDBC使用iBATIS的Oracle SQL DATE转换问题

如何解决《通过JavaJDBC使用iBATIS的OracleSQLDATE转换问题》经验,为你挑选了2个好方法。

我目前正在使用Java中的iBATIS来解决Oracle SQL DATE转换问题.

我使用的是Oracle JDBC瘦驱动程序ojdbc14版本10.2.0.4.0.iBATIS版本2.3.2.Java 1.6.0_10-rc2-b32.

问题围绕这个SQL片段返回的DATE类型列:

SELECT *
FROM   TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?)) order by from_date

包过程调用返回一个包含在TABLE中的ref游标,然后很容易读取结果集,就好像是对表的select查询一样.

在PL/SQL Developer中,返回的SQL DATE类型的FROM_DATE列之一具有一天中的时间精度:

Tue Dec 16 23:59:00 PST 2008

但是当我通过iBATIS和JDBC访问它时,该值仅保留精确到白天:

Tue Dec 16 12:00:00 AM PST 2008

这样显示时更清晰:

本来应该:

1229500740000 milliseconds since epoch
Tuesday, December 16, 2008 11:59:00 PM PST

但是得到这个:

1229414400000 milliseconds since epoch
Tuesday, December 16, 2008 12:00:00 AM PST
(as instance of class java.sql.Date)

无论我尝试什么,我都无法公开通过Java JDBC和iBATIS返回的这个DATE列的完整精度.

iBATIS映射的是:

FROM_DATE : 2008-12-03 : class java.sql.Date

目前的iBATIS映射是这样的:


我也尝试过:


要么


但是所有尝试的映射都会产生相同的截断Date值.就好像在iBATIS甚至触及它之前,JDBC已经完成了丢失数据精度的损害.

很明显,当我在PL/SQL Developer中运行与测试脚本相同的SQL片段时,我通过浏览JDBC和iBATIS而失去了一些数据精度.根本不可接受,非常令人沮丧,最终非常可怕.



1> Gwyn Evans..:

完整的信息(它比这里描述的更复杂,可能取决于正在使用的Oracle驱动程序的特定版本)在Richard Yee的答案中 - [现已过期链接到Nabble]


从nabble到期之前快速抓取......

Roger,见:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01

具体来说:简单数据类型DATE和TIMESTAMP发生了什么?本节介绍简单数据类型.:-)

在9.2之前,Oracle JDBC驱动程序将DATE SQL类型映射到java.sql.Timestamp.这有一定意义,因为Oracle DATE SQL类型包含日期和时间信息,java.sql.Timestamp也是如此.由于java.sql.Date不包含时间信息,因此对java.sql.Date的映射更为明显有些问题.RDBMS也不支持TIMESTAMP SQL类型,因此将DATE映射到Timestamp没有问题.

在9.2中,TIMESTAMP支持被添加到RDBMS中.DATE和TIMESTAMP之间的区别在于TIMESTAMP包含纳秒而DATE不包括.因此,从9.2开始,DATE映射到Date,TIMESTAMP映射到Timestamp.不幸的是,如果您依赖DATE值来包含时间信息,则会出现问题.

有几种方法可以解决这个问题:

更改表以使用TIMESTAMP而不是DATE.这可能很少可能,但它是最好的解决方案.

更改应用程序以使用defineColumnType将列定义为TIMESTAMP而不是DATE.这有问题因为你真的不想使用defineColumnType,除非你必须(参见什么是defineColumnType以及何时应该使用它?).

改变应用程序使用getTimestamp而不是getObject.在可能的情况下,这是一个很好的解决方案,但是许多应用程序包含依赖于getObject的通用代码,因此并不总是可行.

设置V8Compatible连接属性.这告诉JDBC驱动程序使用旧映射而不是新映射.您可以将此标志设置为连接属性或系统属性.您可以通过将连接属性添加到传递给DriverManager.getConnection或OracleDataSource.setConnectionProperties的java.util.Properties对象来设置连接属性.您可以通过在java命令行中包含-D选项来设置系统属性.

java -Doracle.jdbc.V8Compatible ="true"MyApp Oracle JDBC 11.1修复了这个问题.从此版本开始,驱动程序默认将SQL DATE列映射到java.sql.Timestamp.无需设置V8Compatible即可获得正确的映射.V8Compatible被强烈弃用.你根本不应该使用它.如果你把它设置为true它不会伤害任何东西,但你应该停止使用它.

尽管很少使用这种方式,但V8Compatible不存在修复DATE to Date问题,而是支持与8i数据库的兼容性.8i(和更早版本)数据库不支持TIMESTAMP类型.设置V8Compatible不仅会导致SQL DATE在从数据库读取时映射到Timestamp,还会导致所有时间戳在写入数据库时​​转换为SQL DATE.由于不支持8i,因此11.1 JDBC驱动程序不支持此兼容模式.因此,不支持V8Compatible.

如上所述,默认情况下,11.1驱动程序在从数据库读取时将SQL DATE转换为Timestamp.这总是正确的做法,9i的变化是一个错误.11.1驱动程序已恢复正常行为.即使您没有在应用程序中设置V8Compatible,在大多数情况下也不应该看到任何行为上的差异.如果使用getObject读取DATE列,您可能会注意到不同之处.结果将是时间戳而不是日期.由于Timestamp是Date的子类,因此这通常不是问题.您可能会注意到的区别在于,您是否依赖于从DATE到Date的转换来截断时间组件,或者您是否对值进行了toString.否则,改变应该是透明的.

如果由于某种原因,您的应用程序对此更改非常敏感,并且您只需要具有9i-10g行为,则可以设置连接属性.将mapDateToTimestamp设置为false,驱动程序将恢复为默认的9i-10g行为并将DATE映射到Date.

如果可能,您应该将列类型更改为TIMESTAMP而不是DATE.

-Richard


Roger Voss写道:我在stackoverflow上发布了以下问题/问题,所以如果有人知道解决方案,那么很高兴看到它在那里得到解答:

通过Java JDBC使用iBATIS的Oracle SQL DATE转换问题

这是问题描述:

我目前正在使用Java中的iBATIS来解决Oracle sql DATE转换问题.

我使用的是Oracle JDBC瘦驱动程序ojdbc14版本10.2.0.4.0.iBATIS版本2.3.2.Java 1.6.0_10-rc2-b32.

问题围绕这个SQL片段返回的DATE类型列:

SELECT*FROM TABLE(pk_invoice_qry.get_contract_rate(?,?,?,?,?,?,?,?,?,?))from_date

包过程调用返回一个包含在TABLE中的ref游标,然后很容易读取结果集,就好像是对表的select查询一样.

在PL/SQL Developer中,返回的SQL DATE类型的FROM_DATE列之一具有一天中的时间精度:

Tue Dec 16 23:59:00 PST 2008

但是当我通过iBATIS和JDBC访问它时,该值仅保留精确到白天:

Tue Dec 16 12:00:00 AM PST 2008

这样显示时更清晰:

原本应该是:1229500740000毫秒,自2008年12月16日星期二,太平洋标准时间晚上11:59:00太平洋标准时间

但改为:1229414400000毫秒,自2008年12月16日星期二,太平洋标准时间上午12点00分(作为类java.sql.Date的实例)

无论我尝试什么,我都无法公开通过Java JDBC和iBATIS返回的这个DATE列的完整精度.

iBATIS映射的是:

FROM_DATE:2008-12-03:class java.sql.Date

目前的iBATIS映射是这样的:

我也尝试过:

要么

但是所有尝试的映射都会产生相同的截断Date值.就好像在iBATIS甚至接触它之前,JDBC已经完成了丢失数据精度的损害.

很明显,当我在PL/SQL Developer中运行与测试脚本相同的SQL片段时,我通过浏览JDBC和iBATIS来减少我的一些数据精度.根本不可接受,非常令人沮丧,最终非常可怕.



2> RogerV..:

我发现了如何解决这个问题.iBATIS允许注册自定义类型处理程序.所以在我的sqlmap-config.xml文件中我添加了这个:



然后添加了这个实现iBATIS TypeHandlerCallback接口的类:

// corrected getResult()/setParameter() to correctly deal with when value is null
public class CustomDateHandler implements TypeHandlerCallback {
    @Override
    public Object getResult(ResultGetter getter) throws SQLException {
        final Object obj = getter.getTimestamp();
        return obj != null ? (Date) obj : null;
    }

    @Override
    public void setParameter(ParameterSetter setter,Object value) throws SQLException {
        setter.setTimestamp(value != null ? new Timestamp(((Date)value).getTime()) : null);
    }

    @Override
    public Object valueOf(String datetime) {
        return Timestamp.valueOf(datetime);
    }
}

当我需要映射Oracle DATE时,我现在就像这样描述它:


推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有