@Transactional 属性:传播、隔离、回滚
引言
声明式事务把事务边界从代码里移到注解上:@Transactional 标注方法/类,事务由代理在调用边界自动开启、提交或回滚。真正要掌握的是注解上那几个属性——传播行为、隔离级别、回滚规则——它们决定事务“怎么嵌套、怎么隔离、何时回滚”。
核心概念
- 开启:纯 Spring 需
@EnableTransactionManagement;Spring Boot 引了spring-boot-starter-jdbc/*-data-jpa等会自动开启(以官方文档为准)。代理模式(默认)下仅拦截 public 方法与外部调用。 - 传播行为(Propagation,默认 REQUIRED):
REQUIRED:有事务就加入,没有就新建;REQUIRES_NEW:总是挂起外层、新开独立事务;NESTED:在保存点(savepoint)上嵌套,内层可单独回滚到保存点;SUPPORTS/NOT_SUPPORTED/MANDATORY/NEVER:可有可无/挂起外层/必须有否则异常/禁止有事务。
- 隔离级别(Isolation,默认 DEFAULT=数据库默认):
READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE;实际效果以数据库实现为准(如 MySQL InnoDB 默认 REPEATABLE_READ,以官方文档为准)。 - 回滚规则(默认):
RuntimeException与Error触发回滚;受检异常默认不回滚。可用rollbackFor = Exception.class扩大,noRollbackFor缩小。 - 其他属性:
readOnly = true是只读提示(优化/校验用,不等于强制禁止写,具体以提供者实现为准)、timeout(秒,超时自动回滚)、rollbackForClassName/noRollbackForClassName。 - 标注位置:类级别=该类所有 public 方法默认值;方法级别覆盖类级别,越具体越优先。
代码示例
@Service
public class OrderService {
@Transactional // REQUIRED + 默认回滚规则
public void createOrder(Order order) {
orderDao.insert(order);
paymentService.pay(order); // REQUIRED:加入当前事务
inventoryService.deduct(order); // REQUIRES_NEW:独立事务
}
}
@Service
public class PaymentService {
@Transactional(propagation = Propagation.REQUIRED)
public void pay(Order order) { /* 与 createOrder 同事务,一起提交/回滚 */ }
}
@Service
public class InventoryService {
// 即使外层稍后回滚,扣减也已独立提交(REQUIRES_NEW 的代价)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deduct(Order order) { /* 独立事务 */ }
@Transactional(rollbackFor = Exception.class, readOnly = false)
public void risky() throws Exception { /* 受检异常也回滚 */ }
}
注意点
REQUIRED嵌套不是“内层独立事务”,内层异常回滚会把整个外层一起带崩;想要局部隔离用REQUIRES_NEW(各自提交)或NESTED(保存点)。- 受检异常默认不回滚是新人第一坑:忘写
rollbackFor = Exception.class,业务异常被“提交”了。 - 代理模式下注解加在接口上只在 JDK 代理+外部调用时有效,官方建议直接标注具体类/方法(以官方文档为准)。
- 隔离级别由数据库实现兜底,
DEFAULT最常见;乱升SERIALIZABLE会显著降并发。 readOnly别当约束用;timeout默认按事务管理器实现,单位秒。
小结
@Transactional 三组关键词:传播(怎么嵌套)、隔离(怎么并发可见)、回滚规则(什么异常算失败)。先背默认值(REQUIRED / DEFAULT / 仅运行时异常回滚),再按业务逐条显式声明,事务行为即可预测。