Spring无自定义异常传播阻断器,精准圈定事务边界靠传播属性:1.用REQUIRES_NEW彻底隔离内外事务;2.NESTED配合保存点实现局部回滚;3.不可用try-catch清除rollback-only状态。
spring 框架本身没有“自定义异常传播阻断器”这个内置组件,所谓“在嵌套事务中精准圈定可达性网络边界”,本质上是对事务传播行为与异常逃逸路径的协同控制——关键不在于拦截异常流,而在于用传播属性切换事务边界,从而限定异常引发的回滚影响范围。
以下三点是真正落地的核心策略:
用
REQUIRES_NEW切断事务上下文链
内层方法标注@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class),它会挂起外层事务、开启全新事务。此时内层抛出任何RuntimeException(如IllegalArgumentException、自定义业务异常),都只回滚自身事务,外层事务完全不受影响,连接、隔离级别、回滚状态全部隔离。这是最彻底的“边界圈定”,适用于日志记录、消息发送、补偿任务等弱一致性环节。用
NESTED+ 显式保存点实现局部回滚
外层用REQUIRED,内层用NESTED,数据库需支持 savepoint(MySQL InnoDB、PostgreSQL 可用)。当内层发生校验失败等非致命异常时,不任其向上逃逸,而是捕获后调用TransactionStatus.setRollbackOnly()或手动回滚到保存点。这样外层事务仍可提交,仅该子流程被撤销。典型场景:批量导入中单条数据格式错误,跳过该条,其余继续处理。绝不依赖
try-catch清除rollback-only状态
在REQUIRED嵌套下,内层一旦抛出未捕获的RuntimeException,整个事务即被标记为rollback-only。此时外层即使catch并吞掉异常,也无法恢复事务可提交状态,最终必报UnexpectedRollbackException。这不是异常没“拦住”,而是事务状态已不可逆——所谓“阻断”,从来不是拦异常,而是换边界。
可达性网络边界的实质,就是事务作用域的物理边界:是否共用同一数据库连接?是否共享同一事务 ID?是否受同一个 rollback-only 标记约束?验证方式很简单:开启 SQL 日志,观察 connectionId 和 XID 是否一致。一致即在同一大边界内,不一致则已成功圈定独立子域。
不复杂但容易忽略:所谓“精准圈定”,靠的不是写一个拦截器,而是选对 propagation 值,并确保跨 Bean 调用(避免 this.method() 导致代理失效)。

















