使用 mvn liquibase:diff 时如何禁用删除表和列?

Posted

技术标签:

【中文标题】使用 mvn liquibase:diff 时如何禁用删除表和列?【英文标题】:How to disable drop table and column when using mvn liquibase:diff? 【发布时间】:2020-02-25 18:33:56 【问题描述】:

我正在设置发布流程,以尽可能轻松地升级我们的生产环境。

为了实现与数据库相关的目标,我选择了 liquibase。 每次升级环境时:

    代码在服务器上交付, 运行mvn liquibase:diff 生成以前版本的changeLog 运行 mvn spring-boot:run 以启动应用程序并使用新的 changeLog 执行 liquibase,从而从新交付的代码实体中调整数据库。

问题在于,如果 java @Entity 中的 字段移动 到另一个实体,liquibase 将删除列而不将数据传输到新的字段位置。

所以我的问题是,我们可以将 liquibase 配置为 avoid 列和表 drop 吗?为了能够将数据复制到新位置,然后有效地永久删除列(或表)?

我们正在使用 spring-boot 2.1.2liquibase maven 插件 3.4.1。我们的数据库位于 MySQL 5.7.27

我试图找到如何导出所有数据库 creation/alteration changeSet 在一个 changeLog.xml 和所有 drop changeSet 在另一个 @987654328 @。 像这样我们可以在这两个changeLog 之间执行,第三个changeLog 专门用于将数据复制到他们的新位置。 Bu 在 liquibase 文档中没有找到解决方案:https://www.liquibase.org/documentation/diff.html

为了说明我的例子:

v1

@Entity
public class Person 
     private long id;
     private String name;
     private String phoneNumber;

成为

v2: (创建实体 Phone 以替换实体 Person 的字段 phoneNumber

@Entity
public class Person 
     private long id;
     private String name;
     private Phone phone;


@Entity
public class Phone 
    private long id;
    private String phoneNumber;
    private String brand;

所以当 v2 在服务器上交付并运行 mvn liquibase:diff 时,结果 changeLog 将 dropphoneNumber 并创建列 电话person表中。 在不从表 person 传输数据的情况下,将 phoneNumber 提交到字段 phoneNumber 中的新表 phone

我想执行将 Person.phoneNumber 复制到新实体 Phone.phoneNumber 的 changeLog(手动编写)。

这可能吗?或者有什么技巧可以正确地做到这一点?或者,也许我正在以不好的方式使用 liquibase 来实现这一目标?

非常感谢!

【问题讨论】:

【参考方案1】:

也许我遗漏了一些东西,但据我了解,diff 并不是可以免除您任何责任的万能工具。

在某些情况下,您必须自己编写变更集,我认为这就是其中之一。

由于diff确实是一个非常强大的命令,它有它的缺点。

查看这篇文章:The Problem With Database Diffs

理论上,差异工具还可以检查新的、更新的和 数据库之间缺少数据,但实际上这不适用于 两个原因:

性能。随着数据集的增长,要比较的信息量也会不断增长,直至无法管理。 更改数据。在开发过程中,测试数据通常被添加到不应复制到其他数据库中的开发数据库中。 此外,新数据可能会添加到测试和生产数据库中 不应该因为它在开发中不存在而被删除 数据库。

在你的情况下,我会做这样的事情:

    新建表phone 添加栏目person.phone_id 将数据从person.phone_number复制到phone.phone_number 将数据从phone.id复制到person.phone_idpersonphone 之间创建外键约束 删除person.phone_number

代码可能是这样的:

<createTable tableName="phone">
    <column name="id" autoIncrement="true" type="bigserial">
        <constraints primaryKey="true" primaryKeyName="pk_phone"/>
    </column>
    <column name="phone_number" type="varchar(30)"/>
    <column name="brand" type="varchar(255)"/>
</createTable>
<addColumn tableName="person">
    <column name="phone_id" type="bigserial"/>
</addColumn>
<update tableName="phone">
    <column name="phone_number" valueComputed="(select p.phone_nubmer from person p)"/>
</update>
<comment>Assuming that person.phone_number is unique</comment>
<update tableName="person">
    <column name="phone_id" valueComputed="(select p.id from person p where p.phone_number = phone_number)"/>
</update>
<addForeignKeyConstraint baseTableName="person" baseColumnNames="phone_id"
    constraintName="person_phone_id_phone_id_fk"
    referencedTableName="phone" referencedColumnNames="id"/>
<dropColumn tableName="person" columnName="phone_number"/>

【讨论】:

感谢您的回答。我们实际上决定用 changeSets 和一些 sql 脚本自己做更多的事情。我们对旧数据库进行转储,运行 liquibase 以更新架构,最后将数据从转储复制到更新后数据库中的新位置。

以上是关于使用 mvn liquibase:diff 时如何禁用删除表和列?的主要内容,如果未能解决你的问题,请参考以下文章

Liquibase:diff 总是生成索引

我不明白 liquibase diff 试图通过这些选择来确定啥?

liquibase diff 不起作用

如何在eclipse中使用mvn clean install

如何使用 mvn site 命令生成集成测试报告

当 jenkins 作业作为“执行 Maven 发布”运行时,如何在 shell 步骤中获取参数 MVN_RELEASE_VERSION 的值?