
当 spring boot 应用使用 mongock 进行 mongodb 数据库迁移时,若因重构导致实体类名、集合名或仓库接口变更,不应修改已发布的迁移文件;正确做法是新增独立变更单元(changeunit)处理数据迁移,并将旧类隔离至专用依赖库以保持迁移逻辑稳定。
当 spring boot 应用使用 mongock 进行 mongodb 数据库迁移时,若因重构导致实体类名、集合名或仓库接口变更,不应修改已发布的迁移文件;正确做法是新增独立变更单元(changeunit)处理数据迁移,并将旧类隔离至专用依赖库以保持迁移逻辑稳定。
在基于 Mongock 的 Spring Boot 项目中,迁移文件(@ChangeUnit 类)本质上是不可变的数据库演进快照——每个变更单元代表数据库从状态 S(0) 到 S(n) 的一个确定性步骤。一旦部署到生产环境,这些文件即成为系统数据一致性的契约。因此,直接修改已存在的 CreateFooChangelog 等历史迁移文件不仅违反幂等性原则,更会导致新环境初始化失败(如 CI/CD 流水线或新服务器部署时找不到 FooDb 类),也破坏了迁移版本的可追溯性与可重复性。
✅ 正确实践应遵循三步策略:
-
保留原始迁移文件原封不动
CreateFooChangelog仍需正常执行(即使其引用的FooDb和FooRepository已从主代码库移除)。为保障运行时可用性,需将这些“已废弃但迁移必需”的类提取至独立模块(如mongock-legacy-models),并通过 Maven/Gradle 引入:<!-- pom.xml --> <dependency><groupid>com.example</groupid><artifactid>mongock-legacy-models</artifactid><version>1.0.0</version></dependency>
此方式既满足 Mongock 运行时反射加载需求,又避免污染主业务代码,符合关注点分离原则。
-
新增专属变更单元处理结构迁移
创建新的@ChangeUnit(如RenameFooToBarChangelog),使用MongoTemplate(而非业务 Repository)执行底层操作,确保不依赖已删除的领域层组件:@ChangeUnit(id = "rename-foo-to-bar", order = "002", author = "team") public class RenameFooToBarChangelog { @Execution public void execute(MongoTemplate mongoTemplate) { // 检查源集合是否存在且非空 if (mongoTemplate.collectionExists("foo") && mongoTemplate.getCollection("foo").countDocuments() > 0) { // 原子性重命名集合(MongoDB 4.4+ 支持 renameCollection 命令) mongoTemplate.getDb().runCommand( new Document("renameCollection", "test.foo") .append("to", "test.bar") .append("dropTarget", true) ); System.out.println("✅ Collection 'foo' renamed to 'bar'"); } else { // 初始化空集合(可选:插入默认数据) mongoTemplate.createCollection("bar"); System.out.println("ℹ️ Collection 'bar' created (empty)"); } } }⚠️ 注意:
renameCollection是数据库级命令,要求目标数据库名称一致(如"test.foo"→"test.bar"),且需确保无并发写入。生产环境建议配合维护窗口执行,并添加异常捕获与日志审计。 -
彻底解耦业务逻辑与迁移逻辑
Mongock 官方强烈建议:迁移方法签名中避免注入MongoRepository或领域实体。原因在于——- Repository 层可能随业务迭代引入
@Query、@Aggregation等强耦合逻辑,导致迁移失败; - 实体类字段变更(如
@Field注解调整)会引发 BSON 序列化不兼容; -
MongoTemplate提供Document/BasicDBObject级 API,完全绕过 ORM 映射,具备最高稳定性与可控性。
- Repository 层可能随业务迭代引入
总结而言,面对类/集合重构,核心原则是:迁移脚本 immutable,数据迁移 explicit,依赖隔离 clean。通过新增变更单元 + 旧模型抽离 + 原生驱动操作,既能保障历史迁移完整性,又能支撑业务持续演进,是 Mongock 场景下最健壮、可维护性最强的解决方案。










