Transactional 注解

总结

整理了 @Transactional 的作用、关键属性、类级别与方法级别的区别、自调用失效问题

起因

在推送成绩的生产问题中,发现对于 Transactional 注解还理解的不够到位,于是有了此篇笔记。

概念

Transactional 注解,主要用于声明方法或者类需要 事务 管理。

Spring 会在方法执行前开启事务,执行成功则提交事务,如果方法抛出未捕获的 异常(默认是 RuntimeException 或 Error),事务会回滚。

作用:

  • 标记方法或类为事务性操作。
  • 控制事务的边界、传播行为、隔离级别、超时等。

关键属性

  • propagation: 定义事务的传播行为(如 REQUIREDREQUIRES_NEW 等,详见 事务的传播行为)。
  • isolation: 设置事务的隔离级别。
  • timeout: 超过指定时间则回滚。
  • readOnly: 是否只读事务。
  • rollbackFor: 指定哪些异常导致事务回滚,默认是所有 RuntimeException 和 Error,但不回滚 Checked Exception
  • noRollbackFor: 指定哪些异常不会导致事务回滚。

类级别 vs 方法级别

场景 类级别 @Transactional 方法级别 @Transactional
作用范围 所有 public 方法,privateprotected 或包可见方法 不会 触发 仅标注的方法
适用场景 类中所有方法都需要事务 只有特定方法需要事务
优先级 方法级别注解会覆盖类级别 更灵活,可单独配置传播行为和隔离级别

实践

使用方法

  • 加在方法上: 仅对该方法启用事务管理。
@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会新建
    }
}

关联文章


文章作者: huan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 huan !
  目录