绑定到Java时间戳对象时,Hibernate忽略数据库时区信息

时间:2018-02-13 02:00:39

标签: java oracle hibernate date

我有一些日期存储在Oracle中,Oracle的TIMESTAMP(3)作为其数据类型。现在我正在编写一个Spring启动应用程序来读取这些值。代码如下:

HibernateCallback callback = new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException {
            Query query = session.createSQLQuery("SELECT date_field FROM some_table WHERE some_conditions");

            return query.list();
        }
    };

所以:

List results = (List)getHibernateTemplate().execute(callback);
// suppose there's only one row and one column returned
Timestamp ts = result.get(0)[0];

返回由Hibernate自动创建的Java Timestamp对象。问题是,在构造对象时,它会忽略存储在Oracle中的时区,而是使用JVM的默认时区。我测试的是为JVM设置不同的时区,每次生成不同的时间戳。

这显然是错的。日期在时间线上应该是唯一的。它不应该依赖于JVM的时区。我想知道在解析日期时包含DB的时区信息的正确方法是什么。现在看起来它只是使用存储在Oracle中的String表示并用JMV的时区解析它。我正在使用Hibernate 4.3.4.Final

PS:实际查询是高度自定义的,所以我必须编写原始SQL。

3 个答案:

答案 0 :(得分:4)

基本上,这甚至不是Hibernate的问题,而是JDBC的问题。默认情况下,JDBC驱动程序将使用运行JVM的系统时区。如果要连接到不同时区的数据库服务器,或者即使您希望独立于系统的当前时区,最好明确设置JDBC时区。 您可以使用Offset(0,1)属性来设置时区,也可以在运行时通过。

执行此操作
hibernate.jdbc.time_zone

对于Oracle,我会说你可以使用session = sessionFactory.withOptions() .jdbcTimeZone(TimeZone.getTimeZone("UTC")) .openSession(); 来尊重你的JDBC客户端时区。

答案 1 :(得分:0)

问题在于您正在使用的Oracle列数据类型,如果您访问官方oracle文档link,您会注意到 TIMESTAMP 不尊重时区,因此您应该与Dictionary<string,IEnumerable<Rate>> groupedSet = new Dictionary<string, IEnumerable<Rate>>(); foreach (var key in currencyCode) { IEnumerable<Rate> _result = rate.Where(x => x.CurrencyCode.Contains(key)); if (_result.Any()) { groupedSet.Add(key, _result); } } TIMESTAMP WITH TIME ZONE一起使用。

enter image description here

答案 2 :(得分:0)

似乎问题在于日期处理的概念很少

  • 如果要在多个时区中使用,则DB中的日期应为UTC。
  • Java程序应将日期转换为所需的时区。

如果您在数据库中根据UTC获取日期,然后检查hibernate查询的输出,您应该看到日期根据JVM的时区进行了更改。

如果您想要返回相同的日期(如在DB中),也许您应该将日期转换为UTC时区。

现在,您可以执行以下任一操作:

  • 将JVM的时区设置为与数据库记录时区相同。不推荐
  • 根据UTC更改数据库中的日期,并将日期更改为JVM的时区。推荐