@Transactional事务传播分析

1.场景一:两个service类 ClassAServiceImpl ,ClassBServiceImpl; A类的testA调用B类的testB方法,A类中testA方法添加事务注解并且调用B类的testB方法时添加try catch,分析testB方法是否添加事务注解对程序的影响。

   

  A类:

@Service
public class ClassAServiceImpl implements IClassAService {

    private final IClassBService iClassBService;

    @Autowired
    public ClassAServiceImpl(IClassBService iClassBService){
        this.iClassBService = iClassBService;
    }

    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testA() {
        // 省略业务代码
        try {
            iClassBService.testB();
        }catch (Exception e){
           // 这里不抛出异常
        }

    }
}

B类:

@Service
public class ClassBServiceImpl implements IClassBService {


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testB() {
        int i = 1 / 0;
    }
}

 

1. testB方法添加事务注解:

    testA方法调用testB,testB抛出异常,然后testA方法中捕获异常,但是不抛出异常,最终程序异常。

    异常信息:Transaction rolled back because it has been marked as rollback-only

   异常解释:testA和testB方法上都添加了事务注解,这时应该存在两个事务,testA的主事务,testB的子事务,事务嵌套执行,当testB子事务发生异常时整个事务已经被标志为需要回滚,这时testA方法里捕获了异常没有抛出,没法进行事务回滚,和事务的标志状     态不一致,导致发生异常。

 

2.testB方法不添加事务注解:

    testA方法调用testB,正常执行。

    解释:这时testB会加入到testA的事务中,相当于只存在一个事务,不存在子事务和主事务的说法,只有当testA事务抛出异常时,整个事务才会被标志为回滚状态。

 

 

 

 

2.场景二:当testA和testB都在A类中时

@Service
public class ClassAServiceImpl implements IClassAService {



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testA() {
        // 省略业务代码
        try {
           testB();
        }catch (Exception e){
           // 这里不抛出异常
        }

    }

   

    
    @Transactional(rollbackFor = Exception.class)
    void testB(){
        // 这里的testB方法没有通过实现接口重写,就是类中一个普通方法
        int i = 1 / 0;
    }
}

1.这时无论testB方法是否添加事务注解,代码都会正常运行。

解释: 同一个类的方法直接调用 testB的事务注解会失效。

 

 

2. 或许有人说通过代理调用就可以使事务注解生效:

@Service
public class ClassAServiceImpl implements IClassAService {



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testA() {
        // 省略业务代码
        try {
            ((ClassAServiceImpl) AopContext.currentProxy()).testB();
        }catch (Exception e){
           // 这里不抛出异常
        }

    }


    @Transactional(rollbackFor = Exception.class)
    void testB(){
        // 这里的testB方法没有通过实现接口重写,就是类中一个普通方法
        int i = 1 / 0;
    }
}

结论: 代码还是正常运行。

解释: AopContext.currentProxy()是获取当前类的代理类(类实现了接口就使用jdk动态代理,否则就是cglib),这里ClassAServiceImpl实现了接口采用jdk动态代理,但是这里testB方法是类的普通方法,没有通过实现接口的方式在类中重写,导致代理失效。

 

 

 

3.testB方法实现接口

@Service
public class ClassAServiceImpl implements IClassAService {



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testA() {
        // 省略业务代码
        try {
            ((IClassAService) AopContext.currentProxy()).testB();
        }catch (Exception e){
           // 这里不抛出异常
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testB() {
        // 实现接口方式
        int i = 1 / 0;
    }


}

这时方法运行就会抛出异常:Transaction rolled back because it has been marked as rollback-only

解决方法:去掉testB方法的事务注解即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值