JPQL CURRENT_TIMESTAMP偏移2小时

时间:2016-04-01 08:10:28

标签: oracle hibernate jpa jpql

当我在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小时。

  1. JPQL(错误)
  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
    
    1. jvm(右)
    2. 虽然简单的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
      
      1. native sql(右)
      2. 我启用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

        这至少有效。但是,我仍然想了解问题所在。

1 个答案:

答案 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.

的含义