
关键在于明确传播行为与异常传播路径的关系。Propagation 不是“自动隔离异常”,而是定义事务边界的创建规则;异常是否触发回滚、是否影响外层,取决于传播类型 + 异常是否逃逸 + 事务是否被标记为 rollback-only。
REQUIRED 是默认值,但不等于“安全共存”
当内外方法都用 REQUIRED(或省略 propagation),它们共享同一物理事务。只要内层抛出未捕获的 RuntimeException,Spring 就会把整个事务标记为 rollback-only。即使外层用 try-catch 捕获了异常,这个状态也不会清除——最终提交时抛 UnexpectedRollbackException。
适用场景:强一致性操作,比如“创建订单 + 扣减库存”,必须同成功、同失败 风险点:日志记录、消息通知等弱一致性环节若也用 REQUIRED,会被主事务拖垮 验证方式:查看数据库连接是否复用(同一 connectionId)、事务 ID 是否一致
REQUIRES_NEW 实现真正的事务解耦
它强制挂起当前事务、开启全新事务,拥有独立的连接、隔离级别和回滚控制。内层失败只回滚自己,不影响外层提交。
典型用途:审计日志、异步通知、补偿任务等“尽力而为”型操作 注意点:每次调用都会申请新连接,高并发下需确认 HikariCP 连接池配置充足 必须跨 Bean 调用:不能在同类中用 this.method(),否则代理失效,REQUIRES_NEW 退化为普通方法调用
NESTED 利用保存点做局部回滚
它不新建事务,而是在当前事务内建一个 JDBC Savepoint。内层异常可回滚到该保存点,外层继续执行。
优势:避免额外连接开销,适合需要“部分回滚”的流程(如批量导入中单条失败) 限制条件:MySQL 5.7+ / PostgreSQL 需支持 savepoint;HikariCP 默认兼容,但某些云数据库(如 PolarDB 旧版)或启用了 statement-cache 的场景可能抛 SQLFeatureNotSupportedException 检查方法:运行时捕获 SQLException,看是否含 “savepoint” 或 “feature not supported” 关键字
异常处理策略要匹配传播行为
仅靠 try-catch 无法挽救 REQUIRED 嵌套中的事务状态。真正可控的方式是组合使用传播属性与异常分类:
对非关键操作,改用 REQUIRES_NEW,并在内层 catch 异常后正常返回,外层无感知 对关键子流程需局部容错,用 NESTED + 显式 TransactionStatus.setRollbackOnly() 或抛出特定异常(如 NestedRollbackException) 避免在 REQUIRED 方法中吞掉 RuntimeException;如需忽略,应声明 noRollbackFor 并确保该异常确实不破坏数据一致性

评论(0)