Spring注解式事务失效问题记录


进入甲方弘康人寿后,搭建保全中心时,遇到的一个问题,同一个类中的一个事务方法调用另一个事务时,第二个事务会失效的问题

本文此次仅仅做个记录,这段时间忙完之后再好好梳理下事务这块。spring事物是基于类和接口的所以只能在类里面调用另一个类里面的事物,同一个类里面调用自己类的事物方法是无效的。

*     spring事物也不要频繁使用,在事物处理的同时操作的第一张表会被限制查看的(即被临时锁住)。数据量大的时候会有一定影响。
 *     解决方法
 *     1.在新增类中调用事务
 *     2.用AopContext代理调用  ps: ((TestTransactional)AopContext.currentProxy()).add1();
 */
本类中的一个事务方法调用第二个事务方法时,第二个事务会失效
package com.huida.investment.controller;

import com.huida.investment.entity.LdcodeEntity;
import com.huida.investment.service.base.LdcodeService;
import org.apache.catalina.core.ApplicationContext;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @description: 事务demo
 *
1.propagation-required: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就新建一个事务;
2.propagation-supports: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就以非事务的方式执行;
3.propagation-mandatory: 支持当前事务,如果有就加入当前事务中;如果当前没有事务,就抛出异常;
4.propagation-requires_new: 新建事务,如果当前存在事务,就把当前事务挂起;如果当前方法没有事务,就新建事务;
5.propagation-not-supported: 以非事务方式执行,如果当前方法存在事务就挂起当前事务;如果当前方法不存在事务,就以非事务方式执行;
6.propagation-never: 以非事务方式执行,如果当前方法存在事务就抛出异常;如果当前方法不存在事务,就以非事务方式执行;
7.propagation-nested: 如果当前方法有事务,则在嵌套事务内执行;如果当前方法没有事务,则与required操作类似;

 * @author: zhanghailang
 * @date: 2020-10-14 14:54
 */
@RestController
public class TestTransactional {
    @Autowired
    LdcodeService ldcodeService;
    @Autowired
    TestTransational2 testTransational2;
    @GetMapping(value = "/get1")
    @Transactional(rollbackFor = Exception.class)
    public String add() throws InterruptedException {
        LdcodeEntity ldcodeEntity = new LdcodeEntity();
        ldcodeEntity.setCodename("事务demo");
        ldcodeEntity.setCodetype("TestTrans9");
        ldcodeEntity.setCode("test129");
        ldcodeService.save(ldcodeEntity);
        List<String> list = ldcodeService.queryTLRiskCode();



//        //本类中新的事务
          //catch 住新事务的异常
//        try {
//            add1();
//        }catch (Exception e){
//            System.out.println("第二个事务的异常被catch");
//        }
//        Thread.sleep(20000);
//        System.out.println("事务结束");

        //使用代理的方式获取本类中第二个事务方法
        ((TestTransactional)AopContext.currentProxy()).add1();


        //从另一个类中调用第二个事物的方法
//        testTransational2.add1();
        throw new RuntimeException("1111");
//        return list.get(1);
    }
    /**
     *     spring事物是基于类和接口的所以只能在类里面调用另一个类里面的事物,同一个类里面调用自己类的事物方法是无效的。
     *     spring事物也不要频繁使用,在事物处理的同时操作的第一张表会被限制查看的(即被临时锁住)。数据量大的时候会有一定影响。
     *     解决方法
     *     1.在新增类中调用事务
     *     2.用AopContext代理调用  ps: ((TestTransactional)AopContext.currentProxy()).add1();
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void add1() {
        //本类中的第二个事务不会生效,无论事务隔离级别是哪种  原因是aop的动态代理

        //TODO
        //如果希望第二个事务可以提前提交,第一个事务回滚时还可以将第二个事务回滚  ?????
        System.out.println("本类中的第二个事务");

        LdcodeEntity ldcodeEntity = new LdcodeEntity();
        ldcodeEntity.setCodename("事务demo");
        ldcodeEntity.setCodetype("NewTestTrans9");
        ldcodeEntity.setCode("ntest139");
        ldcodeService.save(ldcodeEntity);


//        throw new RuntimeException("1111");
        System.out.println("第二个事务#############");
        }

}

将第二个事务方法添加到新增类中,事务才会生效

package com.huida.investment.controller;

import com.huida.investment.entity.LdcodeEntity;
import com.huida.investment.service.base.LdcodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @description: 第二个事务服务类
 * @author: zhanghailang
 * @date: 2020-10-14 16:07
 */
@Component
public class TestTransational2 {
    @Autowired
    LdcodeService ldcodeService ;
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void add1() {
        System.out.println("这是另一个类中的第二个事务");
        LdcodeEntity ldcodeEntity = new LdcodeEntity();
        ldcodeEntity.setCodename("事务demo");
        ldcodeEntity.setCodetype("NewTestTrans8");
        ldcodeEntity.setCode("ntest138");
        ldcodeService.save(ldcodeEntity);
//        throw new RuntimeException("1111");
        System.out.println("第二个事务#############");
    }
}