只会背隔离级别还不够Java 面试更爱问为什么Transactional没生效为什么没回滚传播行为怎么选你必须记住的 3 句话面试直出Spring 事务的本质是AOP 代理 在方法边界管理连接与提交/回滚。Transactional最常见失效原因是自调用同类方法互调绕过代理。回滚默认只对RuntimeException/Error想对受检异常回滚需要显式配置。1. Spring 事务在做什么把“事务边界”绑在方法上当你写Transactional public void foo(){...}Spring 通过代理拦截调用在方法前后做开启事务拿连接、设置隔离级别/只读等执行业务发生异常按规则回滚否则提交面试加分表达Spring 事务不是数据库事务的替代品它只是把 JDBC 事务的 begin/commit/rollback 管理自动化。2. 传播行为不要背全套先抓住 3 个最常用2.1REQUIRED默认有事务就加入没有就新建适用绝大多数业务服务方法2.2REQUIRES_NEW总是新开一个事务挂起外层事务适用你希望“外层失败不影响内层落库”例如记录审计日志或希望内层失败可独立回滚风险提示使用不当会导致事务碎片化、吞吐下降、锁冲突更复杂2.3NESTED基于 savepoint保存点的嵌套事务适用部分回滚但仍希望跟随外层一起提交注意是否真正生效与数据库/事务管理器能力有关3. 最常见的“事务失效”清单线上 80% 都在这失效 1自调用绕过代理同一个类里 A 方法调用 B 方法B 上的Transactional不生效。典型长相你线上真的会遇到createOrder()里直接调用同类的saveOrder()而saveOrder()才标了Transactional更稳的修复方式按推荐顺序拆分 Bean把需要事务的方法挪到另一个 Service让调用经过代理最推荐自注入代理调用通过注入自身的代理对象来调用需要小心循环依赖与可读性不推荐的技巧依赖AopContext.currentProxy()侵入性强容易踩配置坑失效 2方法不是 public常见代理策略下非 public 可能无法被代理。失效 3异常被吞掉catch 了异常但没抛出Spring 认为正常结束就会提交。失效 4多数据源/多事务管理器没指定事务开在 A 库SQL 却跑到 B 库。失效 5异步/新线程新线程不继承线程绑定的连接与事务上下文。4. 回滚规则为什么没回滚默认规则RuntimeException / Error - 回滚Checked Exception - 不回滚你应该能顺口说出受检异常需要rollbackFor Exception.class才会回滚。常见“看似回滚但其实没回滚”的场景事务传播把内部事务独立提交REQUIRES_NEW你在外层 catch 了异常并吞掉再补一个高频线上边界尤其是“写库 发消息/写 MQ”事务回滚只能回滚数据库回滚不了已经发出去的消息/调用出去的 RPC如果你用REQUIRES_NEW让“日志/消息”独立提交要能接受外层失败时日志/消息仍然存在工程建议需要强一致的“落库 发消息”优先考虑 Outbox/本地消息表/CDC 这类模式而不是靠传播行为硬凑5. 实战最佳实践把事务写得更稳原则 1缩短事务不要在事务里做 RPC/大 IO/长时间计算。原则 2一类方法一个事务边界把“纯查询/纯计算”与“写库”分开。原则 3对外部接口做幂等事务回滚只能回滚数据库回滚不了外部副作用。原则 4明确只读事务读多场景可以readOnlytrue配合连接/数据库优化但不要迷信它能解决锁问题。原则 5必要时做重试但要识别死锁/锁等待死锁回滚是正常机制但重试必须保证幂等。6. 线上排查事务相关问题怎么定位现象 1数据没回滚看异常类型是否触发回滚看是否异常被 catch看是否自调用绕过代理现象 2接口变慢/超时先按“锁等待/慢 SQL”排查再看是否事务过长导致持锁时间长现象 3部分数据提交、部分没提交重点检查传播行为尤其是REQUIRES_NEW与多数据源7. 自测清单你要能顺口讲出来QTransactional为什么经常失效A因为事务是代理生效最常见是同类自调用绕过代理。Q为什么抛了异常却没回滚A默认只回滚运行时异常受检异常需要配置rollbackFor。QREQUIRES_NEW适合什么场景A需要独立提交/回滚的小事务例如审计日志但会增加复杂度与冲突。8. 30 秒背诵稿Spring 事务本质是 AOP 代理在方法边界自动管理 JDBC 事务最常见失效是自调用绕过代理。传播行为里 REQUIRED 默认加入或新建事务REQUIRES_NEW 会挂起外层并开启独立事务NESTED 基于保存点做部分回滚。回滚默认只对 RuntimeException/Error 生效受检异常需要 rollbackFor。线上问题优先检查代理调用路径、异常是否被吞、传播行为与多数据源绑定再结合锁等待/慢 SQL 判断是否长事务导致抖动。