Transactional 注解
总结
整理了 @Transactional
的作用、关键属性、类级别与方法级别的区别、自调用失效问题
起因
在推送成绩的生产问题中,发现对于 Transactional 注解还理解的不够到位,于是有了此篇笔记。
概念
Transactional 注解,主要用于声明方法或者类需要 事务 管理。
Spring 会在方法执行前开启事务,执行成功则提交事务,如果方法抛出未捕获的 异常(默认是 RuntimeException
或 Error
),事务会回滚。
作用:
- 标记方法或类为事务性操作。
- 控制事务的边界、传播行为、隔离级别、超时等。
关键属性
- propagation: 定义事务的传播行为(如
REQUIRED
,REQUIRES_NEW
等,详见 事务的传播行为)。 - isolation: 设置事务的隔离级别。
- timeout: 超过指定时间则回滚。
- readOnly: 是否只读事务。
- rollbackFor: 指定哪些异常导致事务回滚,默认是所有
RuntimeException
和Error
,但不回滚Checked Exception
。 - noRollbackFor: 指定哪些异常不会导致事务回滚。
类级别 vs 方法级别
场景 | 类级别 @Transactional |
方法级别 @Transactional |
---|---|---|
作用范围 | 所有 public 方法,private 、protected 或包可见方法 不会 触发 |
仅标注的方法 |
适用场景 | 类中所有方法都需要事务 | 只有特定方法需要事务 |
优先级 | 方法级别注解会覆盖类级别 | 更灵活,可单独配置传播行为和隔离级别 |
实践
使用方法
- 加在方法上: 仅对该方法启用事务管理。
@Transactional
public void updateData() {
// 数据库操作
}
- 加在类上: 该类中所有公共方法(public)都将启用事务管理,每个
public
方法都会在一个单独的事务中执行。
@Transactional
public class MyService {
public void createStu(Stu stu) {
// 事务A(独立)
System.out.println("createStu事务: " + TransactionSynchronizationManager.getCurrentTransactionName());
}
public void deleteStu(Long id) {
// 事务B(独立)
System.out.println("deleteStu事务: " + TransactionSynchronizationManager.getCurrentTransactionName());
}
// 不生效事务
private void logStu(Stu stu) {
System.out.println("No transaction here");
}
}
自调用事务失效问题
@Transactional
public class MyService {
public void createStu(Stu stu) {
// 事务A
System.out.println("createStu事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
}
public void deleteStu(Long id) {
// 事务B
System.out.println("deleteStu事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
this.createStu(new Stu()); // 自调用,事务A不会新建!
}
}
- 直接调用:
// 两个方法的事务 完全独立。
myService.createStu(); // 事务A
myService.deleteStu(); // 事务B
- 内部调用:
myService.deleteStu();
deleteStu()
内部调用createStu()
时,不会新建事务 A,而是共用事务 B(自调用问题)。
- 使用代理对象解决
@Transactional
public class MyService {
@Autowired
private MyService selfProxy;// 注入代理对象
public void createStu(Stu stu) {
// 事务A
System.out.println("createStu事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
}
public void deleteStu(Long id) {
// 事务B
System.out.println("deleteStu事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
selfProxy.createStu(new Stu()); // 通过代理调用,事务A会新建
}
}