当我在JPQL查询中选择CURRENT_TIMESTAMP
时,生成的java.sql.Tiemstamp
关闭2小时。行为发生(大概)在冬季到夏季时间之后切换。在那之前,时间是正确的。
在shell中使用date
的linux系统时间是正确的
从linux机器本身运行本机查询时,{oracle}内的CURRENT_TIMESTAMP
是正确的。
创建new Date()
对象时java内部的时间是正确的
但我从{strong> JPQL 查询CURRENT_TIMESTAMP
得到的java.sql.Tiemstamp
错误/关闭2小时。
当我运行以下查询时(忽略OutboundMessage部分,我只是对此进行了劫持以查询CURRENT_TIMESTAMP的值)。
Query q = getManager().createQuery("select o.id, CURRENT_TIMESTAMP from OutboundMessage o where o.id=11370");
Timestamp current_timestamp = (Timestamp)((Object[])q.getResultList().get(0))[1];
在调试器中,时间戳是这个(我已经修剪了一些属性,所以只剩下相关的属性):
result = {Timestamp@13972} "2016-03-31 14:48:12.432215"
cdate = {Gregorian$Date@13975} "2016-03-31T14:48:12.000+0200"
zoneinfo = {ZoneInfo@12683} "sun.util.calendar.ZoneInfo[id="Europe/Vienna",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=139,lastRule=java.util.SimpleTimeZone[id=Europe/Vienna,offset=3600000,dstSavings=3600000,useDaylight=true,...]"
rawOffset = 3600000
rawOffsetDiff = 0
dstSavings = 3600000
ID = "Europe/Vienna"
zoneOffset = 7200000
daylightSaving = 3600000
forceStandardTime = false
locale = null
虽然简单的new Date()
给出了(7分钟后):
result = {Date@13983} "Thu Mar 31 16:55:07 CEST 2016"
cdate = {Gregorian$Date@13986} "2016-03-31T16:55:07.871+0200"
zoneinfo = {ZoneInfo@12683} "sun.util.calendar.ZoneInfo[id="Europe/Vienna",offset=3600000,dstSavings=3600 000,useDaylight=true,..."
zoneOffset = 7200000
daylightSaving = 3600000
forceStandardTime = false
locale = null
我启用hibernate日志记录的相应本机查询也会产生正确的时间
select outboundme0_.OM_ID as col_0_0_, CURRENT_TIMESTAMP as col_1_0_ from MAILABO_OTS_TEST.TB_OUTBOUND_MESSAGE outboundme0_ where outboundme0_.OM_ID=11370
收益col_1_0_ = 2016-03-31 16:59:16.910065 Europe/Berlin
那么是什么让只 jpql CURRENT_TIMESTAMP错了?
**编辑本节要更清楚一点
我真正想要做的是将当前时间戳与实体本身的阈值时间戳进行比较,如下所示:select o from OutboundMessage o where o.id=11370 and o.someDate < CURRENT_TIMESTAMP
执行此查询时,条件o.someDate < CURRENT_TIMESTAMP
应为true
的时间点不会给我任何结果。
但是当我从hibernate sql logging执行相应的native-sql查询到这个jpql查询时,i(正确)得到1个结果。
我只是在调试时选择了CURRENT_TIMESTAMP
并将java.sql.Timestamp
投射到CURRENT_TIMESTAMP
,以找出我的实体未被选中的原因,然后意识到CURRENT_TIMESTAMP
值已经关闭2小时。
我希望行为是:jqpl - &gt;已翻译为原生查询 - &gt;在db上执行的本机查询 - &gt;结果转换回java类。假设这种行为,我的应用程序的整个java端应该永远不会知道CURRENT_TIMESTAMP拥有的实际值 - 它应该只关注将jpql转换为本机sql并将结果集转换回java对象。
解决方法
我现在最终做的是用{/ p>之类的命名参数替换queryString="...where o.someDate < :referenceTime"
Query query = entityManager.createQuery(queryString);
query.setParameter("referenceTime", new Date());
application/controllers
这至少有效。但是,我仍然想了解问题所在。
答案 0 :(得分:0)
你的问题有点困惑。首先看一下java.sql.timestamp上的Javadoc:
注意:此类型是java.util.Date和单独的纳秒值的组合。只有整数秒存储在java.util.Date组件中。分数秒 - 纳米 - 是分开的。传递一个不是java.sql.Timestamp实例的对象时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件是未知的。因此,Timestamp.equals(Object)方法与java.util.Date.equals(Object)方法不对称。此外,hashCode方法使用底层的java.util.Date实现,因此在其计算中不包括nanos。
由于Timestamp类和上面提到的java.util.Date类之间存在差异,因此建议代码不要将Timestamp值一般视为java.util.Date的实例。 Timestamp和java.util.Date之间的继承关系实际上表示实现继承,而不是类型继承。
所以,似乎建议不要在JPA中做什么,这是(向下?)投射结果。
如果我执行此操作,我会得到预期的结果:
Tuple t = em.createQuery("select u.id, CURRENT_TIMESTAMP from User u where u.id = 1", Tuple.class).getSingleResult();
for ( TupleElement<?> e: t.getElements()) {
System.out.println("Element = "+e.getAlias()+":"+t.get(e));
}
我没有得到你所描述的问题。这给出了与上述相同的时间。
System.out.println( (Timestamp)t.get(1) );
我不确定However i get 0 hits running this in java.