propagation_nested 是基于 jdbc 保存点的伪嵌套事务,依赖 datasourcetransactionmanager 和支持 savepoint 的数据库,在同一物理事务中设置保存点实现局部回滚,非真正嵌套事务。

PROPAGATION_NESTED 在 Spring 中并不是真正意义上的“嵌套事务”,而是基于 JDBC 保存点(Savepoint)实现的伪嵌套行为,仅在使用 JDBC 或支持 Savepoint 的数据源(如 MySQL、PostgreSQL)且事务管理器为 DataSourceTransactionManager 时才有效。
依赖底层数据库的 Savepoint 支持
它不依赖数据库本身的嵌套事务能力(多数关系型数据库并不原生支持真正的嵌套事务),而是在当前事务中设置一个保存点。如果内层逻辑回滚,只回滚到该保存点,外层事务仍可继续提交或回滚。
- 必须使用支持 Savepoint 的 JDBC 驱动(主流数据库基本都支持)
- 事务管理器不能是 JTA(如
JtaTransactionManager),因为 JTA 不支持 Savepoint - 不能与
PROPAGATION_REQUIRED或其他传播行为混用后期望“独立事务上下文”——它始终运行在同一个物理事务中
典型使用方式和效果
当外层方法 A 调用内层方法 B,且 B 标注 @Transactional(propagation = Propagation.NESTED):
- A 开启事务 → 获取 Connection → 设置 Savepoint S1
- B 执行 → 若抛出未被捕获的
RuntimeException,触发回滚到 S1,但 A 的事务不受影响 - A 可继续执行后续逻辑,最终决定 commit 或 rollback 整个事务
注意:B 中主动调用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 或抛出异常,才会触发 Savepoint 回滚;若 B 内部自行捕获异常且不传播,A 完全感知不到。
代码示例(关键点标注)
⚠️ 前提:配置了 DataSourceTransactionManager,数据源开启 auto-commit=false,且数据库支持 Savepoint
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 外层事务:插入订单主表
orderMapper.insert(order);
try {
processPayment(order); // 可能失败,但不影响订单插入
} catch (Exception e) {
log.warn("支付处理失败,已回滚至保存点", e);
}
// 即使 payment 失败,order 仍可提交
notifySuccess(order);
}
@Transactional(propagation = Propagation.NESTED)
public void processPayment(Order order) {
// 内层:扣款、生成流水等操作
paymentMapper.deduct(order.getUserId(), order.getAmount());
transactionMapper.insert(new Transaction(...));
// 若此处抛异常,仅回滚这两步,order 插入不受影响
}
}
常见误区与限制
-
不是新事务:没有新的 TransactionStatus,
isNewTransaction()返回 false - 无法跨线程生效:Savepoint 绑定在当前 JDBC Connection 和线程上,异步调用会丢失上下文
-
不适用于 JPA/Hibernate 的 EntityManager:除非明确使用
JpaTransactionManager并配置jdbcExceptionTranslator,否则可能降级为REQUIRED - 多个 NESTED 方法嵌套时,每个都会新建 Savepoint,回滚只作用于最近一级
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











