spring嵌套调用事务问题

如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点呢?

 在当前含有事务方法内部调用其他的方法(无论该方法是否含有事务),这就属于Spring事务传播机制的知识点范畴了。
 Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:
 1.基于接口代理(JDK代理)基于接口代理
 2.基于CGLib代理(子类代理)基于子类代理

下面列举几个事务的例子可以看下是否生效:

// Service方法
@Transactional
public Employee addEmployee() throws RuntimeException {
    Employee employee = new Employee("3y", 23);
    employeeRepository.save(employee);
    // 假设这里出了Exception
    int i = 1 / 0;
    return employee;
}

// Controller调用
@RequestMapping("/add")
public Employee addEmployee() {
    Employee employee = null;
    try {
        employee = employeeService.addEmployee();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
    return employee;
}

事务可以生效,Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类),Error进行回滚。此处属于运行时异常,因此可以回滚事务。

// @Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void updateOrder(Order order) {
        try {
            // update order
        } catch {
            throw new Exception("更新错误");
        }
    }
   }

这样事务也是不生效的,如果你想触发其他异常的回滚,需要在注解上配置一下,如,可以通过配置@Transactional(rollbackFor = Exception.class)自定义其他回滚类型。
此处贴一张异常继承图:在这里插入图片描述

嵌套事务情况:
1、

// 没有事务的方法去调用有事务的方法
public Employee addEmployee2Controller() throws RuntimeException {
    return this.addEmployee();
}

@Transactional
public Employee addEmployee() throws RuntimeException {
    employeeRepository.deleteAll();
    Employee employee = new Employee("3y", 23);
    // 模拟异常
    int i = 1 / 0;
    return employee;
}

2、

@Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void update(Order order) {
        updateOrder(order);
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateOrder(Order order) {
        // update order
    }
    
}

 Spring事务管理用的是AOP,AOP底层用的是动态代理。所以如果我们在类或者方法上标注注解@Transactional,那么会生成一个代理对象。
在这里插入图片描述显然地,我们拿到的是代理(Proxy)对象,调用addEmployee2Controller()方法,而addEmployee2Controller()方法的逻辑是target.addEmployee(),调用回原始对象(target)的addEmployee()。所以这次的调用压根就没有事务存在,更谈不上说Spring事务传播机制了。以上两种因为它们发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,被调用的都不支持事务。从其他类中调用时是可以生效的,下边这种情况是可以生效的:

@Service
public class TestService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Transactional
    public Employee addEmployee() throws Exception {
        employeeRepository.deleteAll();
        Employee employee = new Employee("3y", 23);
        // 模拟异常
        int i = 1 / 0;
        return employee;
    }
}
@Service
public class EmployeeService {
    @Autowired
    private TestService testService;
    // 没有事务的方法去调用别的类有事务的方法
    public Employee addEmployee2Controller() throws Exception {
        return testService.addEmployee();
    }
}

所以,嵌套事务情况需要停下思考下事务是否生效。事务在业务和技术中还是很重要的,要是生产出现这种问题,直接卷铺盖走人了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码厚炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值