启动嵌套事务时遭遇org.hibernate.StaleStateException问题求助
问题分析与解决方案
核心原因
你遇到的StaleStateException是乐观锁机制触发的预期冲突,本质原因是:
- 原Session的一级缓存中保存着版本号为10的实体快照,Hibernate默认会基于这个快照生成更新语句;
REQUIRES_NEW传播机制会开启全新的事务和Session(Spring整合Hibernate时的默认行为),新Session修改实体后提交,数据库中版本号已变为11,但原Session完全不知道这个变更;- 原事务提交时,仍用旧版本号10生成更新语句,数据库中找不到匹配的行,直接触发乐观锁异常。
可行解决方案
1. 强制刷新原Session中的实体
在原事务继续执行(提交前),调用Hibernate Session的refresh()方法,强制从数据库拉取实体的最新状态:
// 原事务中,在提交前执行 session.refresh(yourWorkspaceEntity);
这样原Session的一级缓存会被数据库的最新版本(11)覆盖,后续提交时就能用正确的版本号生成更新语句。注意:如果原事务之前对实体做了未提交修改,refresh会直接覆盖这些修改,需要提前处理数据合并逻辑。
2. 调整事务传播策略(业务允许的情况下)
如果业务上不需要独立的新事务,把Propagation.REQUIRES_NEW换成Propagation.REQUIRED,这样所有操作都在同一个事务和Session中执行,实体版本号会实时更新,不会出现跨Session的版本不一致问题。
3. 避免跨事务修改同一实体(从业务逻辑层面优化)
乐观锁的设计初衷就是阻止并发修改同一数据,如果你能调整业务流程,让原事务结束后再执行新事务,或者用其他方式同步数据,就能从根源上避免这个冲突。
关于Flush Mode的说明
把Flush Mode从AUTO改成COMMIT后情况更糟,是因为COMMIT模式下,原事务的修改会延迟到提交时才刷入数据库,而新事务已经提前修改了数据,原事务提交时的冲突不仅没解决,还因为延迟刷新导致问题发现更晚,所以这个调整方向不对。
内容的提问来源于stack exchange,提问作者bednee
相关产品推荐
相关产品推荐

