java - spring.jpa.properties.hibernate.jdbc.time_zone 适用于写入但不适用于读取?

标签 java postgresql hibernate jpa jdbc

我正在使用:

  • Spring Boot 2.0.4.RELEASE
  • spring-data-jpa 2.0.9.RELEASE
  • hibernate-core 5.2.17.Final
  • hibernate-jpa-2.1-api 1.0.0.Final
  • postgres jdbc 驱动程序 42.2.9

我有以下实体:

@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyEntity implements Serializable
{
    @Column(nullable = false, updatable = false)
    @CreatedDate
    private LocalDateTime createdDate;

    @Column(nullable = false)
    @LastModifiedDate
    private LocalDateTime lastModifiedDate;

    public LocalDateTime getCreatedDate()
    {
        return createdDate;
    }

    public LocalDateTime getLastModifiedDate()
    {
        return lastModifiedDate;
    }
}

并在 application.yaml 中设置以下属性:

spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          time_zone: UTC

无论 JVM 时区/默认时区是什么,我都想以 UTC 格式保存和返回时间戳。

出于测试目的,我已将应用程序代码的时区设置为美国/夏威夷:

TimeZone.setDefault(TimeZone.getTimeZone("US/Hawaii"));

当我保存实体时,它会使用 UTC 时间戳正确写入数据库:

[16:43:04.636Z #4c5.042 TRACE -            -   ] o.h.t.d.sql.BasicBinder: binding parameter [1] as [TIMESTAMP] - [2020-03-02T06:43:04.581]
[16:43:04.645Z #4c5.042 TRACE -            -   ] o.h.t.d.sql.BasicBinder: binding parameter [2] as [TIMESTAMP] - [2020-03-02T06:43:04.581]
[16:43:04.649Z #4c5.042 TRACE -            -   ] o.h.r.j.i.ResourceRegistryStandardImpl: Closing prepared statement [HikariProxyPreparedStatement@336047848 wrapping insert into myentity (createdDate, lastModifiedDate) values ('2020-03-02 16:43:04.581+00', '2020-03-02 16:43:04.581+00')]

但是,当我再次读取它时,它会返回为我在应用程序代码中设置的默认时区:US/Hawaii,而不是UTC:

[16:43:04.692Z #4c5.043 TRACE -            -   ] o.h.t.d.sql.BasicExtractor: extracted value ([createdD4_0_0_] : [TIMESTAMP]) - [2020-03-02T06:43:04.581]
[16:43:04.692Z #4c5.043 TRACE -            -   ] o.h.t.d.sql.BasicExtractor: extracted value ([lastModi5_0_0_] : [TIMESTAMP]) - [2020-03-02T06:43:04.581]
[16:43:04.695Z #4c5.043 TRACE -            -   ] o.h.l.p.e.p.i.ResultSetProcessorImpl: Done processing result set (1 rows)
[16:43:04.696Z #4c5.043 TRACE -            -   ] o.h.l.p.e.p.i.AbstractRowReader: Total objects hydrated: 1
[16:43:04.696Z #4c5.043 TRACE -            -   ] o.h.l.p.e.p.i.ResultSetProcessingContextImpl: Skipping create subselects because there are fewer than 2 results, so query by key is more efficient.
[16:43:04.696Z #4c5.043 TRACE -            -   ] o.h.r.j.i.ResourceRegistryStandardImpl: Releasing result set [HikariProxyResultSet@622126582 wrapping org.postgresql.jdbc.PgResultSet@3f0764b8]
[16:43:04.696Z #4c5.043 TRACE -            -   ] o.h.r.j.i.ResourceRegistryStandardImpl: Closing result set [HikariProxyResultSet@622126582 wrapping org.postgresql.jdbc.PgResultSet@3f0764b8]
[16:43:04.696Z #4c5.043 TRACE -            -   ] o.h.r.j.i.ResourceRegistryStandardImpl: Releasing statement [HikariProxyPreparedStatement@1612081040 wrapping select myentity0_.createdDate as createdD4_0_0_, myentity0_.lastModifiedDate as lastModi5_0_0_, where myentity0_.id='123']

我尝试将 serverTimezone=UTC&useLegacyDatetimeCode=false 添加到我的 JDBC URL,但没有任何区别。

也许相关:https://hibernate.atlassian.net/browse/HHH-13417

非常感谢任何帮助。

更新

根据 @midhun mathew 的回答,我发现控制应用程序代码中的日期设置就足以解决此问题(也从 application.yaml 中删除 time_zone 属性):

myEntity.setCreatedDate(LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC))
public void setCreatedDate(LocalDateTime createdAt) 
{ 
  this.createdAt = createdAt; 
}

现在,在写入数据库时​​,日期被“绑定(bind)”并作为 UTC 插入(与原始帖子中的日期“绑定(bind)”为 US\Hawaii,但插入为 UTC):

[10:10:21.475Z #065.042 TRACE -            -   ] o.h.t.d.sql.BasicBinder: binding parameter [1] as [TIMESTAMP] - [2020-03-03T10:10:17.400]
[10:10:21.476Z #065.042 TRACE -            -   ] o.h.t.d.sql.BasicBinder: binding parameter [2] as [TIMESTAMP] - [2020-03-03T10:10:17.400]
[HikariProxyPreparedStatement@860888944 wrapping insert into myentity(createdDate, lastModifiedDate) values ('2020-03-03 10:10:17.4-10', '2020-03-03 10:10:17.4-10')]
[10:10:21.479Z #065.042 TRACE -            -   ] 

从数据库读取实体时,日期不再读取为 US/Hawaii,而是 UTC:

[10:10:24.527Z #065.043 TRACE -            -   ] o.h.t.d.sql.BasicExtractor: extracted value ([createdD4_0_0_] : [TIMESTAMP]) - [2020-03-03T10:10:17.400]
[10:10:24.527Z #065.043 TRACE -            -   ] o.h.t.d.sql.BasicExtractor: extracted value ([lastModi5_0_0_] : [TIMESTAMP]) - [2020-03-03T10:10:17.400]

最佳答案

我也遇到过同样的问题。我的数据库时区是 UTC,我的应用程序时区是新加坡。 我通过让实体和表都具有 UTC 日期来解决这个问题,这样它们之间就不需要进行转换。然后我在 getter 和 setter 中的代码中进行了时间戳之间的转换。

因此,您的 MyEntity 类将以 UTC 格式存储createdAt 和lastModifiedAt。

在 setter 中你可以有类似的东西

public void setCreatedDate(LocalDateTime createdAt)
{         
    this.createdAt = createdAt.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

在 setter/getter 中你可以有类似的东西

public LocalDateTime getCreatedDate()
{         
    return createdAt.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

您可能还需要删除时区属性以及 @CreatedDate 和 @LastModifiedDate 注释,因为这会转换时间。

关于java - spring.jpa.properties.hibernate.jdbc.time_zone 适用于写入但不适用于读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60493632/

相关文章:

java - mysql第一次完美连接,第二次返回空指针

Django - 在 ArrayField 中查询最新日期

php - 在 PHP (plphp) 中,我们如何使用 Imagick 管理存储在 bytea 中的文件?

spring - setFirstResult 和 setMaxResult 不适用于 Order By

java - 在一些 Hibernate 关系映射方面需要帮助

java - 如何解压http响应?

java - SmartGWT 中的 addMembers(...) 和 setMembers(...) 有什么区别

postgresql - SQL窗口函数检测列值的变化

java - 如何在Spring中使用Template Hibernate保存继承的类

java - 更新我的 HashSet 中的一些元素