【问题标题】:Hibernate not correctly storing ZonedDateTime as datetimeoffset in SQL ServerHibernate 没有正确地将 ZonedDateTime 存储为 SQL Server 中的 datetimeoffset
【发布时间】:2016-06-18 22:02:45
【问题描述】:

我想在 SQL Server 2008 中使用 datetimeoffset 列来存储日期和时间以及时区。

数据库中列的DDL定义:

LastUpdatedDateTime datetimeoffset DEFAULT SysDateTimeOffset()

使用 Hibernate 映射的实体上字段的 Java 定义:

private ZonedDateTime lastUpdatedDateTime = ZonedDateTime.now();

我正在使用 Hibernate 5.1.0.Final(通过 Spring boot 1.3.2.RELEASE)并包括 org.hibernate:hibernate-java8。

观察到的行为(通过使用 WinSQL 查询数据库): 通过 SQL 插入语句插入数据会导致存储正确的日期和时间以及正确的时区:2016-03-03 13:41:17.5358944 -07:00

通过保存 Java 实体插入数据(根据上面的 Java 代码片段初始化字段)。 Java 将日期/时间值(保存前)报告为:2016-03-04T14:18:17.076-07:00[America/Denver]

保存后,WinSQL将数据库中存储的值报告为:2016-03-04 14:18:17.0760000 +00:00

这具有相同的日期和时间,但时区错误(UTC 而不是 -07:00)。

当我在 Java 中使用 Timestamp 而不是 ZonedDateTime 声明该字段时,我得到了相同的行为。

如何正确存储时区?我真的不在乎它是存储为 UTC 还是 -07:00 时区,只要基于时区的时间是正确的。我认为 Hibernate 会为此提供支持(在 hibernate-java8 库中),并且我不必编写自定义转换器或自定义用户数据类型。

【问题讨论】:

  • 我倾向于坚持使用 Timestamp,因为我在使用 Hibernate 5 时遇到了其他问题,可能会阻止我使用它的 hibernate-java8 库。

标签: java sql-server hibernate


【解决方案1】:

我终于找到了解决办法:

  1. 对实体字段使用 java.time.OffsetDateTime 而不是 ZonedDateTime。根据 Javadoc 类,OffsetDateTime 旨在用于数据库持久性。

  2. 恢复到 Hibernate 4(由于我遇到的其他问题)。因此,如果您将 Hibernate 5 与 hibernate-java8 库一起使用,我不知道是否需要执行后续步骤。

  3. 添加一个从 OffsetDateTime 到 String 的 Hibernate 转换器。显然,默认情况下,JDBC 将 datetimeoffset 列视为字符串(而不是 Microsoft JDBC 驱动程序文档建议的 microsoft.sql.DateTimeOffset 类)。此转换器中的逻辑必须处理 SQL Server 仅存储 7 位纳秒数而 OffsetDateTime 提供 9 位的复杂性。

  4. 确保转换器包含在 Hibernate EntityManager 中。

这些步骤的详细信息如下:

DDL 列定义不变。

实体字段定义:

private OffsetDateTime lastUpdatedDateTime;

转换器类:

@Converter(autoApply = true)
public class OffsetDateTimeConverter implements AttributeConverter<OffsetDateTime, String> {

    private static DateTimeFormatter FORMATTER_FROM_DB = DateTimeFormatter.ofPattern(
      "yyyy-MM-dd HH:mm:ss.nnnnnnn xxx");
    private static DateTimeFormatter FORMATTER_TO_DB = DateTimeFormatter.ofPattern(
      "yyyy-MM-dd HH:mm:ss.nnnnnnnnn xxx");

    @Override
    public String convertToDatabaseColumn(OffsetDateTime attribute) {
        if (attribute == null) {
            return null;
        }
        return attribute.format(FORMATTER_TO_DB);
    }

    @Override
    public OffsetDateTime convertToEntityAttribute(String dbData) {
        if (dbData == null) {
            return null;
        }
        return OffsetDateTime.parse(dbData, FORMATTER_FROM_DB);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-16
    • 2021-07-17
    • 2018-11-10
    • 2019-09-02
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多