Spring Data MongoRepository save(T) 偶发失效问题求助
排查MongoRepository save()偶发不持久化的问题
这种偶发的持久化失效真的很闹心,结合你说的「数据访问类基本没改但代码频繁变动」这个背景,我梳理几个大概率的排查方向,你可以逐一验证:
1. 事务配置的“暗坑”
如果最近业务代码里加了事务相关的逻辑(比如@Transactional注解),哪怕DAO层没动,上层服务的事务配置也可能掉链子:
- 检查是否存在未正确提交的事务:比如事务方法抛出了受检异常(Spring事务默认只回滚RuntimeException),导致整个事务回滚,save()的变更直接被撤销了。
- 确认事务的传播行为:如果调用save()的方法嵌套在另一个事务里,而外层事务最终没提交(比如中途抛出异常),那内层的save()变更也不会持久化。
- 排查小技巧:在调用save()前后打日志,同时对比mongod.log——正常save会触发insert/update命令,要是有事务回滚,日志里会有对应的rollback记录。
2. 乐观锁版本冲突(静默失败)
如果你的BookData实体用了@Version注解做乐观锁控制,多个线程同时改同一个文档时,版本号不匹配会导致save()静默失败(Spring Data MongoDB默认不会抛异常,这坑很多人踩过):
- 先检查实体类里有没有类似
@Version private Long version;的字段。 - 解决办法:把乐观锁改成显式抛出异常的方式,这样冲突时能立刻发现:
之后版本冲突就会抛出@Document(collection = "bookData") public class BookData { @Id private String id; @Version(type = VersionType.EXPLICIT) private Long version; // 其他业务字段 }OptimisticLockingFailureException,再也不用猜来猜去了。
3. MongoDB写关注点配置过低
如果最近调整过MongoDB的连接配置,写关注点(Write Concern)设置太松可能导致“假成功”:
- 默认Spring Data MongoDB的写关注点是
ACKNOWLEDGED(MongoDB确认写入才返回),但如果被改成了UNACKNOWLEDGED,MongoDB不会确认写入就给客户端返回成功,偶发情况下就会出现写入丢失。 - 检查你的application.yml/properties:
建议直接设成spring.data.mongodb.write-concern: acknowledgedMAJORITY(集群多数节点确认写入),稳定性更高。
4. 实体对象状态被误判
MongoRepository的save()是“智能”的:有非空ID就更新,没ID就插入。要是对象状态被误判,就会出问题:
- 比如代码里不小心把实体的ID置空了,save()就会执行插入而不是更新,看起来像是原有数据没变化;或者客户端生成的ID重复,导致插入失败(不过这种一般会抛
DuplicateKeyException,但并发场景下可能偶发)。 - 排查小技巧:调用save()前打印对象的ID和所有字段,确认是要更新还是插入。
5. 缓存拖了后腿
如果最近加了Spring Cache之类的缓存逻辑,可能出现“数据已经持久化,但查出来的是旧缓存”的假象:
- 比如调用save()后没更新/清除对应缓存,后续查询直接从缓存取旧数据,误以为save()没生效。
- 解决办法:检查缓存注解(
@CachePut、@CacheEvict)是否配对了,确保save()操作后同步更新缓存。
最后:从mongod.log挖线索
你给的正常日志是find命令,建议对比失败时的mongod.log:
- 如果失败时根本没出现insert/update命令,说明save()连数据库都没调用,问题出在Spring层(比如事务拦截、缓存拦截);
- 如果有insert/update命令,但
nModified或nInserted是0,说明没有文档被修改/插入,结合上面的方向排查就行。
内容的提问来源于stack exchange,提问作者walen
相关产品推荐
相关产品推荐

