事务传播行为
一、7 种传播行为
┌─────────────────────────────────────────────────────────────────┐
│ 7 种事务传播行为 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ REQUIRED(默认) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 有事务 → 加入 │ │
│ │ 无事务 → 创建新事务 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ REQUIRES_NEW │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 总是创建新事务 │ │
│ │ 挂起当前事务(如果有) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ SUPPORTS │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 有事务 → 加入 │ │
│ │ 无事务 → 非事务执行 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ NOT_SUPPORTED │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 非事务执行 │ │
│ │ 挂起当前事务(如果有) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ MANDATORY │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 有事务 → 加入 │ │
│ │ 无事务 → 抛异常 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ NEVER │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 非事务执行 │ │
│ │ 有事务 → 抛异常 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ NESTED(嵌套事务) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 有事务 → 创建嵌套事务(savepoint) │ │
│ │ 无事务 → 创建新事务(等同 REQUIRED) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘二、REQUIRED vs REQUIRES_NEW
┌─────────────────────────────────────────────────────────────────┐
│ REQUIRED vs REQUIRES_NEW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ REQUIRED(共享事务): │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 外层事务 │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 内层方法 │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ 同一事务,外层提交才都提交 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ REQUIRES_NEW(独立事务): │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 外层事务 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 内层方法(新事务) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ 独立事务,各自提交/回滚 │
│ │
└─────────────────────────────────────────────────────────────────┘三、NESTED 嵌套事务
┌─────────────────────────────────────────────────────────────────┐
│ NESTED 嵌套事务 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 使用数据库 Savepoint 机制 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 外层事务 │ │
│ │ │ │
│ │ savepoint: sp1 │ │
│ │ │ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 嵌套事务 │ │ │
│ │ │ 嵌套失败 → rollback to sp1 │ │ │
│ │ │ 外层继续 │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ 外层提交 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 嵌套失败只回滚到 savepoint,不影响外层 │
│ │
└─────────────────────────────────────────────────────────────────┘四、常见场景
日志记录
java
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log(String operation, String content) {
// 独立事务,即使业务失败日志也应记录
logRepository.save(operation, content);
}发送消息
java
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
// 发送消息,即使失败也不影响订单创建
try {
messageService.sendOrderCreated(order);
} catch (Exception e) {
log.error("发送消息失败", e);
}
}财务转账
java
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
// 扣款
accountRepository.reduceBalance(fromId, amount);
// 存款(嵌套事务,失败不影响扣款)
try {
accountService.deposit(toId, amount);
} catch (Exception e) {
// 记录异常,不回滚主事务
log.error("存款失败", e);
}
}
@Transactional(propagation = Propagation.NESTED)
public void deposit(Long accountId, BigDecimal amount) {
accountRepository.addBalance(accountId, amount);
}五、事务失效场景
1. 非 public 方法
java
@Service
public class UserService {
@Transactional // 不生效!Spring AOP 只支持 public 方法
private void save(User user) {
// ...
}
}2. 内部调用
java
@Service
public class UserService {
@Transactional
public void methodA() {
methodB(); // this.methodB(),不经过代理
}
@Transactional // 不生效!
public void methodB() {
// ...
}
}3. 异常被吞
java
@Transactional
public void save(User user) {
try {
// 业务
} catch (Exception e) {
// 异常被吞掉,事务不回滚
}
}4. 传播行为错误
java
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void save(User user) {
// NOT_SUPPORTED 会挂起事务,变成非事务执行
}六、面试高频问题
Q1: REQUIRED 和 REQUIRES_NEW 区别?
- REQUIRED:共享当前事务,没有则创建
- REQUIRES_NEW:总是创建新事务,挂起旧事务
Q2: NESTED 和 REQUIRED 区别?
- REQUIRED:共享事务
- NESTED:使用 savepoint,嵌套部分失败只回滚到 savepoint
Q3: 什么情况下事务会失效?
- 非 public 方法
- 内部调用(this.xxx())
- 异常被 catch 吞掉
- 传播行为设置为 NOT_SUPPORTED
Q4: 默认对哪些异常回滚?
RuntimeException 和 Error,不对 Checked Exception 回滚(除非配置 rollbackFor)
七、Spring 全家桶总结
Spring Framework
├── IoC/DI ✅
├── AOP ✅
├── Bean 生命周期 ✅
├── 三级缓存/循环依赖 ✅
└── 动态代理 ✅
Spring Boot
├── 自动配置 ✅
├── starter ✅
├── 配置文件 ✅
└── 条件装配 ✅
Spring MVC
├── 请求处理流程 ✅
├── 参数绑定 ✅
├── 视图解析 ✅
├── 拦截器/过滤器 ✅
└── 异常处理 ✅
Spring Data
├── JDBC ✅
├── JPA ✅
├── Redis ✅
└── 事务管理 ✅
Spring Security
├── 认证/授权 ✅
├── JWT ✅
├── RBAC ✅
└── OAuth2 ✅
Spring Cloud
├── Nacos ✅
├── Gateway ✅
├── Feign ✅
├── Sentinel ✅
└── Config ✅Spring 系列文档全部完成! 🎉