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

时间:2019-06-08 16:53:22

标签: java mysql jpa migration database-migration

我有一个使用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;
    }
}

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

1 个答案:

答案 0 :(得分:1)

我将尝试的操作(备份数据库之后!):

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

  • JPA impl(休眠吗?)应将DateTime存储为TIMESTAMP
  • JDBC驱动程序应该能够将TIMESTAMP放入LocalDateTime

也请考虑使用ZonedDateTime而不是LocalDateTime