Hibernate 未正确解析 DST 转换周围的值

Hibernate not parsing values around DST transitions correctly

我遇到了一个问题,在 DST 转换期间发生的 Instant 被正确地保存到数据库中,但是当回读时返回不同的值。

具体来说,我在 Europe/London 并且 2021-10-31T01:04:00Z 有问题 - 我回来的瞬间是 2021-10-31T00:04:00Z.

我已经创建了一个简单的应用程序来演示这一点 - 它持续存在三个事件,一个在 DST 转换之前,一个是之前提到的唯一一个在 DST 转换期间,然后一个在 DST 转换之后。我希望输入和输出数据始终相同。

输出如下:

ZoneId=Europe/London

Persisting:
2021-10-30T01:04:00Z
2021-10-31T01:04:00Z
2021-11-01T01:04:00Z

Native Query:
clob1: '2021-10-30 02:04:00+01'
clob2: '2021-10-31 01:04:00+01'
clob3: '2021-11-01 01:04:00+00'

Hibernate Object:
2021-10-30T01:04:00Z
2021-10-31T00:04:00Z
2021-11-01T01:04:00Z

:

import java.text.MessageFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Properties;
import java.util.stream.Stream;    
import org.h2.Driver;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.H2Dialect;

public class StoreData {
  public static void main(final String[] args) {
    System.out.println(MessageFormat.format("ZoneId={0}", ZoneId.systemDefault()));

    final Properties properties = new Properties();
    properties.setProperty(AvailableSettings.DIALECT, H2Dialect.class.getName());
    properties.setProperty(AvailableSettings.URL, "jdbc:h2:mem:test");
    properties.setProperty(AvailableSettings.DRIVER, Driver.class.getName());

    try (Session session = new Configuration().setProperties(properties).addAnnotatedClass(Event.class)
      .buildSessionFactory().openSession()) {
      final Transaction transaction = session.beginTransaction();

      // Table creation done explicitly to show types used
      session.createSQLQuery("CREATE TABLE EVENT(ID BIGINT, DATE TIMESTAMP WITH TIME ZONE)").executeUpdate();

      System.out.println("Persisting:");
      Stream.of("2021-10-30T01:04:00Z", "2021-10-31T01:04:00Z", "2021-11-01T01:04:00Z").map(Instant::parse)
        .forEach(instant -> {
          System.out.println(instant);
          final Event e = new Event();
          e.setDate(instant);
          e.setId(instant.toEpochMilli());
          session.persist(e);
        });

      transaction.commit();
      System.out.println();

      System.out.println("Native Query:");
      session.createNativeQuery("SELECT CAST(date as TEXT) FROM event").getResultList()
        .forEach(System.out::println);

      System.out.println();

      System.out.println("Hibernate Objects:");
      session.getEntityManagerFactory().createEntityManager().createQuery("FROM Event", Event.class)
        .getResultList().stream().map(Event::getDate).forEach(System.out::println);
    }
  }
}

:

import java.time.Instant;    
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Event {
    @Id
    private long id;
    private Instant date;

    public long getId() {
    return id;
    }

    public void setId(final long id) {
    this.id = id;
    }

    public Instant getDate() {
    return date;
    }

    public void setDate(final Instant date) {
    this.date = date;
    }
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.me</groupId>
    <artifactId>help</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.6.7.Final</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.210</version>
        </dependency>
    </dependencies>
</project>

有趣的是,如果我迁移到 Hibernate v6,它看起来能正常工作吗?

ZoneId=Europe/London

Persisting:
2021-10-30T01:04:00Z
2021-10-31T01:04:00Z
2021-11-01T01:04:00Z

Native Query:
clob1: '2021-10-30 01:04:00+00'
clob2: '2021-10-31 01:04:00+00'
clob3: '2021-11-01 01:04:00+00'

Hibernate Objects:
2021-10-30T01:04:00Z
2021-10-31T01:04:00Z
2021-11-01T01:04:00Z

明确地说: Europe/London 时区, H2 内存数据库。

我通过将 AvailableSettings.JDBC_TIME_ZONE 设置为 UTC 并将列类型更改为 TIMEZONE.

来完成此工作

相信这是 Hibernate v5 和 H2 驱动程序之间的不兼容。