spring.jpa.properties.hibernate.jdb c .time_zone применяется для записи, но не для чтения? - PullRequest
0 голосов
/ 02 марта 2020

Я использую:

  • 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 jdb c драйвер 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 / часовой пояс по умолчанию, я хочу сохранить и вернуть временные метки в UT C.

Для целей тестирования я установил часовой пояс моего кода приложения на US/Hawaii:

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

Когда я сохраняю объект, он правильно записывается в база данных с временной меткой UT C:

[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 к моему URL JDB C, но это не имело никакого значения.

Возможно, связано: https://hibernate.atlassian.net/browse/HHH-13417

Любая помощь - это большое приложение reciated.

Обновление

Основываясь на ответе @midhun mathew, я обнаружил, что для решения этой проблемы достаточно установить настройки в коде приложения (удаляя time_zone) свойство из application.yaml):

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

Теперь при записи в БД даты «связаны» и вставляются как UTC (по сравнению с исходным сообщением, в котором даты были «связаны» как 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]

1 Ответ

1 голос
/ 02 марта 2020

Я столкнулся с той же проблемой. Часовой пояс моей базы данных был в UT C, а часовой пояс моего приложения был в Сингапуре. Я решил эту проблему, указав дату и время в UT C и для сущности, и для таблицы, поэтому между ними не требуется преобразование. Затем я сделал преобразования между временными метками в коде в методах получения и установки.

Таким образом, ваш класс MyEntity будет хранить madeAt и lastModifiedAt в UT C.

В установщике вы можете получить что-то как

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

В получателе вы можете получить что-то вроде

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

Возможно, вам также придется удалить свойство часового пояса и аннотации @CreatedDate и @LastModifiedDate, так как это преобразовывало время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...