我目前正在使用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而失去了一些数据精度。根本不可接受,非常令人沮丧,最终非常可怕。
答案 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),问题现在已经消失。