Spring Boot Sping Boot 3 + Hibernate 6迁移:时区Map问题

f45qwnt8  于 2023-02-22  发布在  Spring
关注(0)|答案(1)|浏览(210)

我正在将Sping Boot 2 + Hibernate 5应用程序升级到Spring Boot 3和Hibernate 6。在更新时,我注意到Hibernate 6处理java即时字段到不带时区信息的表列之间的转换的方式与Hibernate 5不同。
在Hibernate 6中,当持久化一个示例字段值为2023-02-20T04:08:00Z的对象时,该值在检索时被Map到2023-02-20T05:08:00Z。正如here所解释的,这可能与MapInstant和Duration字段的新方法有关。
我设法通过向应用程序中每个@Entity类的每个Instant字段添加@JdbcType(InstantAsTimestampJdbcType.class)来解决这个问题。但是,我更愿意为这个问题进行单个集中配置,而不是向应用程序中的每个Instant字段添加注解。我尝试了几种方法:
选项1:添加属性hibernate.timezone.default_storage并尝试所有存储类型选项(源代码):

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

选项2:声明Hibernate属性定制器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吗?或者有更好的方法来解决这个问题吗?

  • 请注意,不能通过修改表列来添加时区信息。*
gz5pxeao

gz5pxeao1#

默认情况下,Hibernate 6将InstantMap到SQL类型代码SqlTypes.TIMESTAMP_UTC。此类型代码(默认情况下)Map到InstantAsTimestampWithTimeZoneJdbcTypeInstantAsTimestampJdbcType,具体取决于DialectTimeZoneSupport的功能。这两个JdbcType都将在将Instant发送到数据库之前将其转换为以UTC表示的时间戳。
如果您设置了hibernate.type.preferred_instant_jdbc_type=TIMESTAMP,那么这将强制Hibernate使用TimestampJdbcType,它将 * 不 * 标准化为UTC,而只是将Instant转换为本地时间戳并将其发送到数据库。
你能试试吗,然后告诉我是否有你想要的效果?

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

相关问题