Spring事务传播的应用

service方法里面调用多个保存方法,加上事务,要求商品基础信息没有出现异常则不回滚,只有当商品信息保存出现异常才回滚,其他保存出异常则不需要回滚,解决如下:
1、service方法加 @Transactional(propagation = Propagation.REQUIRED)
2、方法内调用的方法加@Transactional(propagation = Propagation.REQUIRED_NEW)  意思是:我自己开启新事物,不沿用外面的事务
3、pom引入
    <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-aop</artifactId>

   </dependency>
4、 获取到当前类真正的代理对象,去掉方法即可

       1)、@EnableAspectJAutoProxy(exposeProxy = true):暴露代理对象

       2)、获取代理对象; 
ProductServiceImpl proxy = (ProductServiceImpl) AopContext.currentProxy();
就可以使用代理对象调用各种保存方法,而使得事务生效了

以下代码示例:
/**

     * 大保存...

     * @param productParam

     *

     * 考虑事务....

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

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

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

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

     *      Propagation propagation() default Propagation.REQUIRED;

     *      REQUIRED:(必须):

     *          Support a current transaction, create a new one if none exists.

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

     *      REQUIRES_NEW(总是用新的事务):

     *           Create a new transaction, and suspend the current transaction if one exists.

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

     *      SUPPORTS(支持):

     *          Support a current transaction, execute non-transactionally if none exists.

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

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

     *          Support a current transaction, throw an exception if none exists

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

     *      NOT_SUPPORTED(不支持):

     *          Execute non-transactionally, suspend the current transaction if one exists

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

     *      NEVER(从不使用):

     *           Execute non-transactionally, throw an exception if a transaction exists.

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

     *      NESTED:

     *          Execute within a nested transaction if a current transaction exists,

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

     * 一家人带着老王去旅游;

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

     *      Required:坐老王车

     *      Requires_new:一定得开车,开新的

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

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

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

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

     * 外事务{

     *     A();//事务.Required:跟着回滚

     *     b();//事务.Requires_new:不回滚

     *     //自己给数据库插入数据

     *     int i = 10/0;

     * }

     *

     * Required_new

     * 外事务{

     *     A();Required; A

     *     B();Requires_new B

     *     try{

     *         C();Required; C

     *     }catch(Exception e){

     *         //c出异常?

     *     }

     *     D();Requires_new; D

     *     //给数据库存 --外

     *    // int i = 10/0;

     * }

     *

     * 场景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只要感觉到异常就一定回滚。和外事务是什么传播行为无关。

     *

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

     * 如何让某些可以不回滚

     * 事务Spring中是怎么做的?

     * TransactionManager;

     * AOP做;

     * 动态代理。

     *  hahaServiceProxy.saveBaseInfo();

     *

     *  A{

     *      A(){

     *          B(); //1,2,3

     *          C(); //4,5,6

     *          D(); //7,8,9

     *      }

     *  }

     *

     *  自己类调用自己类里面的方法,就是一个复制粘贴。归根到底,只是给

     *  controller{

     *      serviceProxy.a();

     *  }

     *  对象.方法()才能加上事务。

     *

     *  A(){

     *      //1,2,3,4,5,6,7,8,9

     *      //

     *  }

     *

     *  A{

     *      A(){

     *          hahaService.B();

     *          hahaService.C();

     *          hahaService.D();

     *

     *      }

     *  }

     *

     *  事务的问题:

     *      Service自己调用自己的方法,无法加上真正的自己内部调整的各个事务

     *      解决:如果是  对象.方法()那就好了

     *       1)、要是能拿到ioc容器,从容器中再把我们的组件获取一下,用对象调方法。

     * 复习:事务传播行为,

     * ====================================================================

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

     *

     * 读未提交:

     * 读已提交:

     * 可重复读:

     * 串行化:

     *

     * ===========================================================

     * 异常回滚策略

     * 异常:

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

     *          ArithmeticException ......

     *      编译时异常(受检异常)

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

     *

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

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

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

     */

    @Transactional(propagation = Propagation.REQUIRED)

    @Override

    public void saveProduct(PmsProductParam productParam) {

        ProductServiceImpl proxy = (ProductServiceImpl) AopContext.currentProxy();

        //1)、pms_product:保存商品基本信息

        proxy.saveBaseInfo(productParam);

        //5)、pms_sku_stock:sku_库存表

        proxy.saveSkuStock(productParam);

        /**

         * 以下都可以try-catch互不影响

         */

        //2)、pms_product_attribute_value:保存这个商品对应的所有属性的值

        proxy.saveProductAttributeValue(productParam);

        //3)、pms_product_full_reduction:保存商品的满减信息

        proxy.saveFullReduction(productParam);

        //4)、pms_product_ladder:满减表

        proxy.saveProductLadder(productParam);

        //以上的写法只是相当于一个saveProduct事务。

    }
 

/**

     * 保存商品基础信息

     */

    @Transactional(propagation = Propagation.REQUIRES_NEW)

    public void saveBaseInfo(PmsProductParam productParam){

        //1)、pms_product:保存商品基本信息

        Product product = new Product();

        BeanUtils.copyProperties(productParam,product);

        productMapper.insert(product);

        //mybatis-plus能自动获取到刚才这个数据的自增id

        log.debug("刚才的商品的id:{}",product.getId());

        threadLocal.set(product.getId());

        log.debug("当前线程....{}-->{}",Thread.currentThread().getId(),Thread.currentThread().getName())

    }

    //2)、pms_product_attribute_value:保存这个商品对应的所有属性的值

    @Transactional(propagation = Propagation.REQUIRES_NEW)

    public void saveProductAttributeValue(PmsProductParam productParam){

        List<ProductAttributeValue> valueList = productParam.getProductAttributeValueList();

        valueList.forEach((item)->{

            item.setProductId(threadLocal.get());

            productAttributeValueMapper.insert(item);

        });

        log.debug("当前线程....{}-->{}",Thread.currentThread().getId(),Thread.currentThread().getName());

    }
 

@Transactional(propagation = Propagation.REQUIRES_NEW)

    public void saveSkuStock(PmsProductParam productParam) {

        List<SkuStock> skuStockList = productParam.getSkuStockList();

        for (int i = 1; i<=skuStockList.size(); i++) {

            SkuStock skuStock = skuStockList.get(i-1);

            if(StringUtils.isEmpty(skuStock.getSkuCode())){

                //skuCode必须有  1_1  1_2 1_3 1_4

                //生成规则  商品id_sku自增id

                skuStock.setSkuCode(threadLocal.get()+"_"+i);

            }

            skuStock.setProductId(threadLocal.get());

            skuStockMapper.insert(skuStock);

        }

        log.debug("当前线程....{}-->{}",Thread.currentThread().getId(),Thread.currentThread().getName());

    }
 

@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = {Exception.class})

    public void saveFullReduction(PmsProductParam productParam) {

        List<ProductFullReduction> fullReductionList = productParam.getProductFullReductionList();

        fullReductionList.forEach((reduction)->{

            reduction.setProductId(threadLocal.get());

            productFullReductionMapper.insert(reduction);

        });

        log.debug("当前线程....{}-->{}",Thread.currentThread().getId(),Thread.currentThread().getName());

    } 

/**

     * 默认出任何都回滚?

     *

     * @param productParam

     */

    @Transactional(propagation = Propagation.REQUIRES_NEW,

            rollbackFor = FileNotFoundException.class,

    noRollbackFor = {ArithmeticException.class,NullPointerException.class})

    public void saveProductLadder(PmsProductParam productParam) {

        List<ProductLadder> productLadderList = productParam.getProductLadderList();

        productLadderList.forEach((productLadder)->{

            productLadder.setProductId(threadLocal.get());

            productLadderMapper.insert(productLadder);

        });

        log.debug("当前线程....{}-->{}",Thread.currentThread().getId(),Thread.currentThread().getName());

//        int i = 10/0;

//        File xxxx = new File("xxxx");

//        new FileInputStream(xxxx);

    }

发布了5 篇原创文章 · 获赞 0 · 访问量 119

猜你喜欢

转载自blog.csdn.net/u012939253/article/details/105557359