SpringBoot 事务注解使用以及使用中的坑(直接调用自身方法的不生效)

考虑事务使用地方:

      1)、哪些东西是一定要回滚的、哪些即使出错了不必要回滚的。

           商品的核心信息(基本数据、sku---销售属性)保存的时候,不要受到别的无关信息的影响。

           无关信息出问题,核心信息也不用回滚的。

      2)、事务的传播行为;propagation:当前方法的事务[是否要和别人公用一个事务]如何传播下去(里面的方法如果用事务,是否和他公用一个事务)

           REQUIRED:(必须):

               如果以前有事务,就和之前的事务公用一个事务,没有就创建一个事务;

          REQUIRES_NEW(总是用新的事务):

               创建一个新的事务,如果以前有事务,暂停前面的事务。

           SUPPORTS(支持):

               之前有事务,就以事务的方式运行,没有事务也可以;

           MANDATORY(强制):没事务就报错

               一定要有事务,如果没事务就报错

           NOT_SUPPORTED(不支持):

               不支持在事务内运行,如果已经有事务了,就挂起当前存在的事务

           NEVER(从不使用):

                不支持在事务内运行,如果已经有事务了,抛异常

           NESTED:

               开启一个子事务(MySQL不支持),需要支持还原点功能的数据库才行;

形象例子说明以上传播行为

      一家人带着老王去旅游;

           一家人:开自己的车还是坐老王的车

           Required:坐老王车

           Requires_new:一定得开车,开新的

           SUPPORTS:用车,有车就用,没车走路;

           MANDATORY:用车,没车就骂街。。。

           NOT_SUPPORTED:不支持用车。有车放那不用

           NEVER:从不用车,有车抛异常

 

例题感受实际用法

      外事务{
          A();//事务.Required:如果执行到最后一句10/0,出错,跟着回滚
          b();//事务.Requires_new:如果执行到最后一句10/0,出错,不回滚
          int i = 10/0;
      }
     外事务{
          调用A()方法;Required; A
          调用B()方法;Requires_new B
          调用C()方法;Required; C

          //try{

              //C();Required; C

          //}catch(Exception e){

              //c出异常?

          //}

          调用D()方法;Requires_new; D
          //给数据库存 --外
        
      }

 

在上面的例子为前提判断下面场景,哪些会回滚

      场景1:

           A方法出现了异常:由于异常机制导致代码停止,下面无法执行,数据库什么都没有

      场景2:

          C方法出现异常:A回滚,B成功,C回滚,D无法执行,外无法执行

      场景3:

           外成了后,接着执行int i = 10/0: B,D成功。A,C,外都执行了但是必须回滚

      场景4:

          D炸:抛异常。外事务感知到异常。A,C回滚,外执行不到,D自己回滚,B成功

      场景5:

          C用try-catch执行:C出了异常回滚,由于异常被捕获,外事务没有感知异常。A,B,D都成,C自己回滚

     

      总结:

           传播行为过程中,只要Requires_new被执行过就一定成功,不管后面出不出问题。异常机制还是一样的,出现异常代码以后不执行。

      Required只要感觉到异常就一定回滚。和外事务是什么传播行为无关。

      传播行为总是来定义,当一个事务存在的时候,他内部的事务该怎么执行。

 

事务的问题:

public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveProduct(PmsProductParam productParam) {
        //1.保存商品表的基本信息,返回商品id,供下面其他信息保存关联使用
        saveBaseInfo(productParam);
        //2.保存sku库存信息
        saveSkuStock(productParam);
        //3.保存满减价格
        saveFullReduction(productParam);
        //4.保存会员价格
        saveMemberPrice(productParam);
        //5.保存商品参数及自定义规格属性
        saveProductAttributeValue(productParam);
    }

//声明事务传播性为REQUIRES_NEW,调用这个方法的下面其他语句,就算出错,此方法也不会回滚
 @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void saveBaseInfo(PmsProductParam productParam) {
    //执行方法。。。。
}

    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void saveSkuStock(PmsProductParam productParam) {
    //执行方法。。。。
}

    @Transactional(rollbackFor = Exception.class)
    public void saveFullReduction(PmsProductParam productParam) {
    int i=5/0;
    //执行方法。。。。
}

    @Transactional(rollbackFor = Exception.class)
    public void saveMemberPrice(PmsProductParam productParam) {
    //执行方法。。。。
}
    @Transactional(rollbackFor = Exception.class)
    public void saveProductAttributeValue(PmsProductParam productParam) {
    //执行方法。。。。
}

}
  1. 在上面saveProduct方法中,里面有一堆方法,用来保存商品,折扣,满减信息....到数据库。
  2. 然后每个方法加上事务注解,前两个为REQUIRES_NEW,后两个方法为默认REQUIRES,我们这样设计是为了保证不会全部回滚,因为有些重要的信息还是要保存的,省的在前端又填一遍。
  3. 我们在第三个方法saveFullReduction加入了一句错误语句,等执行到他的时候,看起来像是我们期待的样子,前两个不回滚,数据库有数据。
  4. 但实际上却不会生效,因为注解事务实际上是通过AOP代理实现的,saveProduct方法里调用的其他方法只是把其他方法里的语句粘贴过来而已,并不会有事务,所以这样就是一个出错,整体回滚。

解决办法:使用AopContext.currentProxy() 解决Spring注解失效,这个方法可以调用到此类的代理类,通过调用代理类的各个方法,这样就都有事务了,会生效了。

1.第一步将saveProduct()方法改成这样

    public void saveProduct(PmsProductParam productParam) {
        ProductServiceImpl proxy = (ProductServiceImpl) AopContext.currentProxy();
        //1.保存商品表的基本信息,返回商品id,供下面其他信息保存关联使用
        proxy.saveBaseInfo(productParam);
        //2.保存sku库存信息
        proxy.saveSkuStock(productParam);
        //3.保存满减价格
        proxy.saveFullReduction(productParam);
        //4.保存会员价格
        proxy.saveMemberPrice(productParam);
        //5.保存商品参数及自定义规格属性
        proxy.saveProductAttributeValue(productParam);
    }

  2.开启暴露代理类注解

@EnableAspectJAutoProxy(exposeProxy = true)

@SpringBootApplication
public class GmallPmsApplication {

    public static void main(String[] args) {
        SpringApplication.run(GmallPmsApplication.class, args);
    }

}

 

事务传播行为:

      隔离级别:解决读写加锁问题的(数据底层的方案)。  可重复读(快照); 

           运行时异常(不受检查异常)

               ArithmeticException ......

           编译时异常(受检异常)

                 FileNotFound;1)要么throw要么try- catch

运行的异常默认是一定回滚

编译时异常默认是不回滚的;

rollbackFor:指定哪些异常一定回滚的。

     

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值