关于@Transactional的propagation属性深入理解

关于@Transactional的propagation属性深入理解

一、@Transactional注解的作用

Spring框架中的@Transactional注解用于声明式事务管理。它通过AOP(面向切面编程)实现,能够自动管理事务的创建、提交和回滚。开发者只需在方法或类上添加此注解,即可将数据库操作纳入事务控制,无需手动编写事务管理代码。

二、propagation属性详解

propagation属性定义了事务的传播行为,即多个事务方法相互调用时的处理逻辑。以下是其常见取值:

  • REQUIRED(默认值):如果当前存在事务,则加入该事务;否则新建一个事务。
  • REQUIRES_NEW:始终新建事务,若当前存在事务则将其挂起。
  • SUPPORTS:当前存在事务则加入,否则以非事务方式运行。
  • NOT_SUPPORTED:以非事务方式执行,若当前存在事务则挂起。
  • MANDATORY:必须存在事务,否则抛出异常。
  • NEVER:必须非事务执行,否则抛出异常。
  • NESTED:如果当前存在事务,则在嵌套事务内执行。

三、通过案例深入理解传播行为

1. REQUIRES_NEW 场景分析

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog(String userId) {
    //其他jdbc操作 未标注任何@Transactional注解
    userDao.update(userId,"未标注");
    // 独立事务立即提交 insertLog()方法上也标注了@Transactional(propagation = Propagation.REQUIRES_NEW)
    logDao.insertLog(userId);  
    // 模拟异常
    int a = 1/0; 
}
public void logPayment(String orderId) {
    logDao.find(userId);
}
问题1:当auditLog外层事务回滚时,logDao日志记录是否会保留?

答案:会保留,不会回滚,REQUIRES_NEW事务已独立提交

问题2:注释掉模拟异常代码,在insertLog事务结束后,auditLog事务还未结束,其他事务(logPayment)能否查询到更新的日志?

答案:可以立即查询到,REQUIRES_NEW事务提交后数据立即可见

2. REQUIRED 场景分析

@Transactional
public void placeOrder() {
    orderDao.createOrder();    // 操作1
    paymentService.process();  // REQUIRED传播
    inventoryService.deduct(); // 操作3
}
问题1:若process()方法抛出异常,所有操作是否回滚?

答案:是,REQUIRED共享同一事务

3. SUPPORTS 场景分析

@Transactional(propagation = Propagation.SUPPORTS)
public User getUser(String id) {
    return userDao.findById(id); // 随调用方事务状态
}
问题1:非事务环境下执行是否会加锁?

答案:不会,以非事务方式执行查询

4. NOT_SUPPORTED 场景分析

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void refreshCache() {
    cacheDao.clear();  // 强制非事务执行
    cacheDao.reload();
}
问题1:在事务中调用是否影响当前事务?

答案:会挂起事务,后续操作失去原子性

5. MANDATORY 场景分析

@Transactional(propagation = Propagation.MANDATORY)
public void updateBalance(String userId) {
    accountDao.deduct(userId, 100); // 必须存在事务
}
问题1:非事务环境下调用会怎样?

答案:抛出IllegalTransactionStateException

6. NEVER 场景分析

@Transactional(propagation = Propagation.NEVER)
public void generateReport() {
    reportDao.createDailyReport(); // 禁止事务环境
}
问题1:在事务中调用会怎样?

答案:立即抛出异常,终止执行

7. NESTED 场景分析

@Transactional
public void orderProcess() {
    orderDao.create(); // 主事务
    try {
        inventoryService.deduct(); // 嵌套事务
    } catch (Exception e) {
        // 处理异常继续执行
    }
    paymentService.process(); // 主事务
}
问题1:deduct()失败是否影响主事务?

答案:不会,嵌套事务独立回滚

四、其他


class Test{
@Transactional
public void orderProcess1() {
    orderDao.create(); // 主事务
    orderProcess2();
}
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void orderProcess2() {
    orderDao.updateById(); // 主事务
}
}
问题1:同一个类中使用@Transactional会导致事务失效?

答案:会,Spring 的事务管理是基于代理的,直接调用同一个类中的方法不会触发事务代理

五、核心结论

  • REQUIRES_NEW:独立事务,适合审计日志等隔离需求
  • SUPPORTS:灵活适应调用方事务状态,优化查询性能
  • MANDATORY:强制事务保障核心业务数据安全
  • NESTED:实现复杂业务流程的部分回滚控制
  • 根据业务需求选择传播行为,避免事务滥用
  • Spring 的事务管理是基于代理的,直接调用同一个类中的方法不会触发事务代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值