Spring Boot 3 + Hibernate 6 迁移:时区映射问题

2023-12-26

我正在将 Spring Boot 2 + Hibernate 5 应用程序升级到 Spring Boot 3 和 Hibernate 6。更新时,我注意到 Hibernate 6 处理 java Instant 字段到没有时区信息的表列之间的转换的方式与 Hibernate 5 不同。

在 Hibernate 6 中,当持久化一个实例字段具有值的对象时2023-02-20T04:08:00Z,该值被映射到2023-02-20T05:08:00Z检索后。正如所解释的here https://thorben-janssen.com/hibernate-6-offsetdatetime-and-zoneddatetime/这可能与映射“即时”和“持续时间”字段的新方式有关。

我设法通过添加来解决这个问题@JdbcType(InstantAsTimestampJdbcType.class)给每个Instant领域中的每一个@Entity应用程序中的类。但是,我宁愿对此事进行单一的集中配置,而不是向应用程序中的每个 Instant 字段添加注释。我尝试了几种方法:

选项 1:添加属性hibernate.timezone.default_storage并尝试了所有存储类型选项(source https://thorben-janssen.com/hibernate-6-offsetdatetime-and-zoneddatetime/#5_different_TimezoneStorageTypes):

spring.jpa.properties.hibernate.timezone.default_storage=NORMALIZE_UTC

选项 2:声明 HibernatePropertiesCustomizer bean:

    @Bean
    public HibernatePropertiesCustomizer hibernatePropertiesCustomizerPG() {

        return hibernateProperties -> {
            hibernateProperties.put(EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS,
                    (TypeContributorList) () -> List.of(
                            (TypeContributions typeContributions, ServiceRegistry serviceRegistry) ->
                                    typeContributions.contributeJdbcType(InstantAsTimestampJdbcType.INSTANCE)));
        };
    } 

选项 3:创建HibernatePropertiesCustomizer:

@Configuration
public class HibernateTypeContributorConfiguration implements HibernatePropertiesCustomizer {

    @Override
    public void customize(Map<String, Object> hibernateProperties) {
        hibernateProperties.put(
                EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS,
                (TypeContributorList) () -> List.of((jdbcType, serviceRegistry) -> jdbcType.contributeJdbcType(InstantAsTimestampJdbcType.INSTANCE))
        );
    }
}

不幸的是,到目前为止,这些方法都没有奏效。有谁知道如何InstantAsTimestampJdbcType可以注册吗?或者有更好的方法来解决这个问题吗?

请注意,修改表列以添加时区信息不是一种选择。


默认情况下,Hibernate 6 映射Instant到 SQL 类型代码SqlTypes.TIMESTAMP_UTC。此类型代码(默认情况下)映射到InstantAsTimestampWithTimeZoneJdbcType or InstantAsTimestampJdbcType取决于的能力Dialect's TimeZoneSupport。这两个JdbcTypes 将转换Instant在将其发送到数据库之前,先将其转换为以 UTC 表示的时间戳。

如果你设置hibernate.type.preferred_instant_jdbc_type=TIMESTAMP,那么这应该强制 Hibernate 使用TimestampJdbcType,这将not归一化为 UTC,并且将简单地转换Instant到本地时间戳并将其发送到数据库。

您能尝试一下吗?请告诉我是否有您想要的效果?

PS请注意,使用@JdbcTypeCode(TIMESTAMP) or @JdbcType(TimestampJdbcType.class)应该与配置属性具有相同的效果。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot 3 + Hibernate 6 迁移:时区映射问题 的相关文章

随机推荐