使用mvn liquibase:diff时禁用表列删除及实现数据迁移的方案咨询
当然可行!而且这是用Liquibase管理生产环境数据库变更时的标准最佳实践——先迁移数据,再清理旧结构。针对你的场景,我给你梳理几个具体的实现技巧,同时纠正下你之前可能踩的使用误区:
1. 先让Liquibase别自动生成删除语句
你的核心痛点是liquibase:diff会直接生成删列的changeSet,所以第一步要修改插件配置,禁用自动删除的diff类型。在pom.xml的Liquibase插件配置里加这些参数:
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>3.4.1</version> <configuration> <!-- 你的数据库连接、changelog路径等原有配置 --> <diffChangeLogFile>src/main/resources/db/changelog/changelog-diff.xml</diffChangeLogFile> <!-- 直接排除删除类的变更生成 --> <diffExcludeObjects>dropTable,dropColumn</diffExcludeObjects> <!-- 或者更严格:只允许生成新增/修改类的变更 --> <diffTypes>createTable,addColumn,modifyDataType,addForeignKeyConstraint</diffTypes> </configuration> </plugin>
这样再跑mvn liquibase:diff,只会生成创建phone表、给person加phone_id外键这些新增结构的变更,不会碰旧的phoneNumber列。
2. 把变更拆成三个明确的阶段执行
你之前想拆分changeLog的思路完全正确,只是要按执行顺序来组织:
- 阶段1:搭好新结构:先运行上面生成的diff changeLog,创建
phone表和person的关联字段。这一步只做结构新增,不碰旧数据和旧列。 - 阶段2:手动写数据迁移的changeSet:这一步是核心,你需要自己编写SQL把
person.phoneNumber的数据迁移到phone表,同时关联person和phone的关系。比如:
<changeSet id="migrate-person-phone-data" author="your-team"> <!-- 用原生SQL更灵活,适合复杂迁移场景 --> <sql> -- 先给每个有手机号的Person插入对应的Phone记录 INSERT INTO phone (phone_number) SELECT phone_number FROM person WHERE phone_number IS NOT NULL; -- 关联Person和Phone(这里假设Phone的id是自增主键,根据你的实际情况调整) UPDATE person p JOIN phone ph ON p.phone_number = ph.phone_number SET p.phone_id = ph.id; </sql> </changeSet>
- 阶段3:清理旧结构:等数据迁移验证无误后,再手动写删除
person.phoneNumber列的changeSet,或者临时放开diff的删除限制生成语句,执行清理。
3. 结合Spring Boot的自动执行逻辑
Spring Boot会自动执行db/changelog/db.changelog-master.xml里的所有changeSet,所以你可以把三个阶段的文件按顺序引入:
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"> <!-- 先跑新增结构的变更 --> <include file="changelog-diff.xml"/> <!-- 再跑数据迁移 --> <include file="changelog-migrate-phone-data.xml"/> <!-- 最后清理旧列(先注释,验证没问题再打开) --> <!-- <include file="changelog-clean-old-phone-column.xml"/> --> </databaseChangeLog>
这样启动Spring Boot应用时,Liquibase会按顺序执行前两个阶段,等你确认数据没问题后,再把第三阶段的注释去掉,重新启动执行清理。
4. 纠正你的使用误区
liquibase:diff是辅助工具,不是万能的自动生成器——它只能帮你生成结构变更,但涉及数据迁移的场景,必须手动编写对应的changeSet。你之前想拆分创建和删除到不同文件的思路是对的,但核心是要控制执行顺序:先搭新结构,再迁数据,最后删旧结构,而不是单纯按变更类型拆分文件。
最后给你梳理下针对示例场景的完整流程:
- 写完v2的
Person和Phone实体; - 跑
mvn liquibase:diff生成新增结构的changeLog; - 手动编写数据迁移的changeSet;
- 启动Spring Boot,Liquibase自动执行前两个阶段;
- 验证数据迁移正确后,添加删除旧列的changeSet,再次启动完成清理。
这样就能完美实现你想要的“先迁数据再删旧列”的需求了!
内容的提问来源于stack exchange,提问作者MatthieuBlm
相关产品推荐
相关产品推荐

