
当 Spring Boot 应用使用 Mongock 进行 MongoDB 迁移时,若因重构导致实体类、Repository 或集合名变更(如 FooDb → BarDb),不应修改已发布的迁移文件;正确做法是新增独立变更单元(ChangeUnit)处理数据迁移,并将旧类隔离至专用依赖库以保持迁移逻辑稳定。
当 spring boot 应用使用 mongock 进行 mongodb 迁移时,若因重构导致实体类、repository 或集合名变更(如 `foodb` → `bardb`),不应修改已发布的迁移文件;正确做法是新增独立变更单元(changeunit)处理数据迁移,并将旧类隔离至专用依赖库以保持迁移逻辑稳定。
Mongock 的核心设计原则是幂等性与不可变性:每个 @ChangeUnit 代表数据库从状态 S(i) 到 S(i+1) 的确定性演进步骤。一旦部署到生产环境,已有迁移文件即成为“历史契约”——修改它们会破坏新环境初始化的可靠性(例如 CI/CD 部署或本地重装数据库时),并可能导致版本不一致、重复执行异常或校验失败。
因此,面对类名与集合名变更(如 @Document("foo") → @Document("bar")),应严格遵循以下三步实践方案:
✅ 正确做法:新增变更单元 + 隔离旧类依赖
保留原始迁移文件不变
原CreateFooChangelog仍需存在且不可修改。它继续负责在全新环境中创建foo集合及初始数据——这是 Mongock 版本控制的基础保障。-
新增一个独立的
@ChangeUnit处理重命名逻辑
创建如RenameFooToBarChangelog,使用底层驱动操作(推荐MongoTemplate),避免强依赖已删除的FooRepository或FooDb:@ChangeUnit(id = "rename-foo-to-bar", order = "002", author = "team", description = "Rename 'foo' collection to 'bar' and migrate data") public class RenameFooToBarChangelog { @Execution public void execute(MongoTemplate mongoTemplate) { // 检查源集合是否存在 if (mongoTemplate.collectionExists("foo")) { // 执行原子重命名(MongoDB 4.4+ 支持 renameCollection 命令) mongoTemplate.getDb().getCollection("foo").rename("bar"); System.out.println("✅ Collection 'foo' renamed to 'bar'"); } else { // 若 'foo' 不存在,则直接初始化 'bar'(可选默认数据) mongoTemplate.save(new BasicDBObject("default", true), "bar"); System.out.println("ℹ️ Collection 'bar' initialized with default data"); } } @RollbackExecution public void rollback(MongoTemplate mongoTemplate) { // 可选:提供逆向操作(如将 bar 改回 foo),增强可维护性 if (mongoTemplate.collectionExists("bar")) { mongoTemplate.getDb().getCollection("bar").rename("foo"); } } } -
将已废弃的
FooDb、FooRepository等类移入独立 Maven/Gradle 模块
新建模块(如mongock-legacy-models),仅包含迁移所需的历史实体与接口,并在主项目中以compileOnly或runtimeOnly方式引入:<!-- pom.xml --> <dependency><groupid>com.example</groupid><artifactid>mongock-legacy-models</artifactid><version>1.0.0</version><scope>runtime</scope><!-- 仅在运行时加载,编译期不污染主代码 --></dependency>
这样既满足 Mongock 在执行旧迁移时对
FooDb类型的反射需求,又避免主工程维护冗余代码,实现关注点分离。
⚠️ 注意事项与最佳实践
-
永远不要在
@Execution方法中注入已删除的 Repository:FooRepository已不存在时,Spring 将启动失败。务必改用MongoTemplate或MongoDatabase直接操作 BSON/JSON。 -
重命名操作需考虑 MongoDB 版本兼容性:
renameCollection在分片集群中受限,生产环境建议先备份再操作,并添加异常兜底(如try-catch+ 日志告警)。 -
启用 Mongock 的
failFast=false并配合spring.mongock.enabled=true:确保迁移失败时应用仍可启动(便于排查),同时明确启用迁移机制。 -
迁移脚本需通过集成测试验证:模拟从空库开始,依次执行
001-CreateFooChangelog→002-RenameFooToBarChangelog,验证最终bar集合数据完整性。
综上,Mongock 迁移的本质是数据库状态机演进,而非代码逻辑快照。拥抱“新增而非修改”的哲学,辅以依赖隔离与底层驱动操作,才能在持续重构中兼顾稳定性、可追溯性与可维护性。










