如何在已有Spring项目中添加版本注解并兼容MongoDB存量文档
解决Spring Data MongoDB添加@Version后无法更新存量文档的问题
问题根源
Spring Data MongoDB的@Version乐观锁默认逻辑是:当实体存在id但version字段为null时,会判定该实体为新文档(isNew=true),调用insert而非update操作。而存量文档本身已有id但无version字段,此时调用save()就会触发唯一键冲突。
解决方案:自定义IsNew策略,无需批量更新存量文档
你不需要手动修改所有存量文档,只需要覆盖框架的isNew判定逻辑,让框架在实体有id时,即使version为null也判定为非新文档,从而走update流程,框架会自动为存量文档初始化version值。
1. 实现自定义IsNewStrategy
创建一个自定义策略类,仅通过id是否存在来判断是否为新文档:
import org.springframework.data.mapping.model.IsNewStrategy; public class IdBasedIsNewStrategy implements IsNewStrategy { @Override public boolean isNew(Object entity) { // 这里假设实体类有一个名为"id"的主键字段,可根据实际调整 try { java.lang.reflect.Field idField = entity.getClass().getDeclaredField("id"); idField.setAccessible(true); Object idValue = idField.get(entity); return idValue == null; } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException("Failed to check entity ID for isNew determination", e); } } }
2. 在实体类上绑定自定义策略
在你的MongoDB实体类上添加@IsNewStrategyAnnotation注解,指定自定义策略,同时保留@Version注解:
import org.springframework.data.annotation.Version; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mapping.model.IsNewStrategyAnnotation; @Document(collection = "your_collection_name") @Version @IsNewStrategyAnnotation(IdBasedIsNewStrategy.class) // 绑定自定义策略 public class YourEntity { @org.springframework.data.annotation.Id private String id; @Version private Long version; // 其他业务字段及getter/setter }
3. 验证效果
- 当你从数据库查询存量文档(无
version字段)时,实体的version属性为null,但自定义策略会判定isNew=false,触发update操作。 - Spring Data MongoDB会自动为该文档插入
version: 0的字段,后续更新时version会正常递增,乐观锁逻辑生效。 - 如果手动构造一个带
id但数据库中不存在的实体,调用save()会触发更新失败(而非插入),符合预期。
关键说明
- 无需批量更新存量文档:第一次更新时框架会自动初始化
version为0,后续所有操作都遵循乐观锁规则。 - 自定义策略仅影响
isNew判定,不改变@Version的核心乐观锁逻辑。
内容的提问来源于stack exchange,提问作者Parthasarathy
相关产品推荐
相关产品推荐

