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

时间:2008-12-20 21:49:54

标签: java oracle date jdbc ibatis

我目前正在使用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映射是:

<result property="from_date" jdbcType="DATE" javaType="java.sql.Date"/>

我也试过了:

<result property="from_date" jdbcType="DATETIME" javaType="java.sql.Date"/>

<result property="from_date" jdbcType="TIMESTAMP" javaType="java.sql.Timestamp"/>

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

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

7 个答案:

答案 0 :(得分:8)

答案 1 :(得分:6)

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

<typeAlias alias="OracleDateHandler" type="com.tideworks.ms.CustomDateHandler"/>
<typeHandler callback="OracleDateHandler" jdbcType="DATETIME" javaType="date"/>

然后添加了这个实现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时,我现在就这样描述它:

<result property="from_date" jdbcType="DATETIME" javaType="date"/>

答案 2 :(得分:2)

我使用jdbcType =“TIMESTAMP”而不是jdbcType =“DATE”解决了我的问题

•问题:

•解决:

问候。

佩德罗

答案 3 :(得分:1)

问题出在Oracle驱动程序上。

我找到的最佳解决方案是将所有jdbcType =“DATE”更改为jdbcType =“TIMESTAMP” 和#column_name:DATE#到#column_name:TIMESTAMP#

所以改变:

<result property="from_date" jdbcType="DATE" javaType="java.sql.Date"/>

<result property="from_date" jdbcType="TIMESTAMP" javaType="java.sql.Date"/>

答案 4 :(得分:0)

问题在于使用java.sql.Date。根据{{​​3}},java.sql.Date实例包含的毫秒值必须通过在与实例关联的特定时区中将小时,分钟,秒和毫秒设置为零来“标准化” ,以符合SQL DATE的定义。

答案 5 :(得分:0)

是的,我明白了 - 纯SQL DATE标准必须只存储到日期分辨率。实际上,这是Oracle DATE类型的片段:

  

Oracle支持日期和时间,   虽然与SQL2不同   标准。而不是使用两个   单独的实体,日期和时间,   Oracle只使用一个DATE。日期   type存储在一个特殊的内部   格式不仅包括   月,日和年,也是   小时,分钟和秒。

这表明Oracle的DATE超过了标准的SQL DATE。

嗯,Oracle PL / SQL人员广泛使用DATE来保存它们依赖于第二个分辨率的值。看起来iBATIS需要类似Hibernate sql方言概念,而不是通过java.sql.Date解释DATE,而是可以覆盖并通过java.util.Date解释,Javadocs定义为允许毫秒级分辨率。

不幸的是,当我将映射更改为:

<result property="from_date" jdbcType="DATE" javaType="java.util.Date"/>

<result property="from_date" jdbcType="DATETIME" javaType="java.util.Date"/>

它似乎仍然首先将SQL DATE转换为java.sql.Date并且丢失了时间精度。

答案 6 :(得分:0)

Richard Yee提到Oracle的最新驱动程序解决了这个问题。我可以证实这一点。这里有10.2驱动程序同样的问题,今天升级到ojdbc5.jar(11.2.0.1.0),问题现在已经消失。