Skip to content

Spring 事务传播行为和数据库隔离级别应该怎样选择?

题型:追问 · 传播行为决定调用链怎样共享事务,隔离级别决定并发事务怎样观察数据。

建议回答

传播行为先按业务原子边界选择。REQUIRED 适合大多数“有事务就加入、没有就新建”的场景;REQUIRES_NEW 会挂起外层事务并新开事务,适合确实需要独立提交的记录,但会额外占用连接,并可能让内外事务对锁和数据的预期变复杂;NESTED 通常依赖保存点,只能在同一物理事务内局部回滚,能力取决于事务管理器和数据库。其他传播行为更多用于显式约束是否允许处于事务中。

隔离级别要结合数据库实现和业务不变量选择。读已提交能避免脏读,但同一事务两次查询结果可能变化;可重复读、快照读和串行化在不同数据库上的具体锁与 MVCC 行为不完全一致。即使隔离级别较高,也不能笼统认为所有写偏差、幻读和业务超卖都会自动消失,关键更新仍可能需要条件更新、唯一约束、悲观锁或乐观锁。

事务还应尽量短,把参数校验、耗时计算和远程调用移出持有数据库连接与锁的区间。若必须跨边界协调,要明确采用 Outbox、Saga、可靠消息或补偿等最终一致方案,而不是扩大本地事务想象边界。

方案边界

  • REQUIRES_NEW 的独立提交意味着外层回滚后它可能仍然保留,业务上必须接受这种结果。
  • readOnly = true 更多是给框架和数据库的提示,不能当成强安全控制。
  • 隔离级别越高通常并发代价越大,但实际行为要以所用数据库和 SQL 为准。

进一步追问

  • 为什么同一个类内部调用事务方法可能不生效?
  • 事务提交成功后再发送消息,怎样避免“数据库成功、消息失败”?

易错点

  • 不要把 NESTEDREQUIRES_NEW 都说成独立物理事务。
  • 不要只背隔离级别定义,必须结合数据库 MVCC、锁行为和业务写入方式。
  • 不要在长事务中调用不可控的远程接口,否则会放大锁等待、连接占用和结果未知问题。

知识关系

从当前问题继续深入,或者回到提出这个问题的知识入口。