如何使用更新的 JPA 时间戳字段升级数据库?

Posted

技术标签:

【中文标题】如何使用更新的 JPA 时间戳字段升级数据库?【英文标题】:How to upgrade database with newer JPA timestamp fields? 【发布时间】:2019-10-23 19:00:02 【问题描述】:

我有一个使用 JPA 和 Hibernate 运行的 Spring Boot 应用程序来自动管理我的实体。创建此应用程序时,我使用了不支持 Java 8 DateTime API 的旧版 JPA。但是,在没有太多关于 JPA 的知识的情况下,我在我的实体中使用了 LocalDateTime 并且它有效!不必了解底层数据库结构真是太好了!

到现在……

我正在将 JPA 升级到支持 LocalDateTime 的版本,并且 JPA 使用此字段的方式出现错误。它曾经将此对象保存为我的 mysql 数据库中的 VARBINARY (tinyblob) 字段,但现在它很聪明,希望它是 TIMESTAMP 类型。这意味着当我使用配置 spring.jpa.hibernate.ddl-auto=validate 启动我的应用程序时,我得到了错误:

...
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: 
    Schema-validation: wrong column type encountered in column [answer_time] in table [user_answer]; 
    found [tinyblob (Types#VARBINARY)], but expecting [datetime (Types#TIMESTAMP)]

所以现在我对如何将这些字段转换为新的时间戳类型有点迷茫。我正在考虑使用 FlyWay 编写迁移脚本,但我不知道 JPA 如何将对象存储为 blob。当将VARBINARY 字段打印为字符串时,它是这样的:

¬í sr java.time.Ser]º"H² xpw ã !;:;Ö@x

这是我的实体的样子(在升级过程中没有改变):

@Entity
@Table(name = "user_answer")
public class UserAnswer 
    private Long id;
    private LocalDateTime answerTime;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public LocalDateTime getAnswerTime() 
        return answerTime;
    

    public void setAnswerTime(LocalDateTime answerTime) 
        this.answerTime = answerTime;
    

如何更新我的数据库,以便它将用于存储 LocalDateTime 数据的旧 VARBINARY 字段转换为 TIMESTAMP 字段?

【问题讨论】:

【参考方案1】:

我会尝试什么(在备份数据库之后!):

保留旧的 JPA API + 实现(休眠)版本。 保留旧的 LocalDateTime 字段。 向您的实体添加另一个java.sql.Date 字段。确保对其进行正确注释等,以便 Hibernate 确切知道应该如何定义该列。 对于所有实体: 加载每个实体,读取LocalDateTime,将其转换并存储到DateTime字段merge()。 删除DateTime 字段。 从表中删除旧的LocalDateTime 列。 将DateTime字段的类型更改为LocalDateTime。 升级 JPA API + 实现(休眠)版本。
JPA impl(Hibernate?)应将DateTime 存储为TIMESTAMP。 JDBC 驱动程序应该能够将 TIMESTAMP 提取到 LocalDateTime

另外,考虑ZonedDateTime 而不是LocalDateTime

【讨论】:

java.sql.DateTime 不存在,我认为您的意思是`java.sql.Date` 或java.sql.Timestamp。我想我理解你试图解释的方法,所以我正在尝试。非常感谢。 好吧,也许吧。我脑子里没有 Javadoc :) 但是感谢您的注意,我修复了这个帖子。

以上是关于如何使用更新的 JPA 时间戳字段升级数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JPA 2 实体中映射 postgresql“带有时区的时间戳”

JPA 更新日期时间戳

如何在时间戳字段中仅使用日期来选择记录?

如何使用 JPA 和 Hibernate 在 UTC 时区中存储日期/时间和时间戳

如何更新 Spring Data JPA @Modifying @Query 查询中的 JPA/Hibernate @Version 字段?

如何在 SQLite 中设置自动时间戳?