事物的传播属性

一、事物的传播属性

传播属性当前不存在事物当前存在事物
REQUIRED新建事物使用当前事物
REQUIRES_NEW新建事物挂起当前事物,新建事物
SUPPORTS不使用事物使用当前事物
NOT_SUPPORTED不使用事物挂起当前事物
MANDATORY抛出异常使用当前事物
NEVER不使用事物抛出异常
NESTED新建事物嵌套事物

二、代码演示

github地址:https://github.com/javaDeveloperZeng/example.git
1.建立测试类

@RunWith(SpringJUnit4ClassRunner.class)
//启动Spring
@SpringBootTest
public class TestTwoController {
    Logger logger= LoggerFactory.getLogger(TestController.class);
    @Autowired
    UserService userService;
    @Autowired
    UserServiceTwo userServiceTwo;

    @Test
    public void testMethod(){
        userService.test1();
        logger.debug("----执行结束---");
    }
}

2.建立userService

@Service
@Slf4j
public class UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    UserServiceTwo userServiceTwo;
     @Transactional(propagation=Propagation.REQUIRED)
     public void test1(){
      jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
              "values ('1','a','b','c')");
      System.out.println("userService执行完");
      userServiceTwo.insetData2();
     }
}

3.建立userServiceTwo.java

@Service
@Slf4j
public class UserServiceTwo {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insetData2(){
        jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
                "values ('2','abc','b','c')");
        System.out.println("userServiceTwo执行完");
        throw new RuntimeException("错误");
    }

}

执行测试类查看数据,部分结果
在这里插入图片描述

三、有try 的时候案例

  ServiceA {  
             
         void methodA() {  
             ServiceB.methodB();  
         }  
        
    }  
        
    ServiceB {  
             
         void methodB() {  
         }  
             
    }  

案例1,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED,

1、如果ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,会共用同一个事务,如果出现异常,ServiceA.methodA和ServiceB.methodB作为一个整体都将一起回滚。
2、如果ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。ServiceA.methodA中是不受事务控制的。如果出现异常,ServiceB.methodB不会引起ServiceA.methodA的回滚。

案例2,ServiceA.methodA的事务级别PROPAGATION_REQUIRED,ServiceB.methodB的事务级别PROPAGATION_REQUIRES_NEW,

调用ServiceB.methodB,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务。

1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try…catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。

案例3,ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_NESTED,
调用ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint
1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB也将回滚。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try…catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。

四、事物不生效情况

修改UserService .java中test1调用本类方法test2。期望结果是test1中执行插入语句回滚,test2中隔离级别REQUIRES_NEW是新开的事物不应该回滚。但是真实结果test1和test2中执行插入都回滚。test2中事物失效。

@Service
@Slf4j
public class UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    UserServiceTwo userServiceTwo;
     @Transactional(propagation=Propagation.REQUIRED)
     public void test1(){
      jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
              "values ('1','a','b','c')");
      System.out.println("tes1执行完");
      this.test2();
      throw new RuntimeException("出错");
     }
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void test2(){
        jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
                "values ('2','aaa','b','c')");
        System.out.println("test2执行完");
    }

}

解决方法1:在类内部通过@Autowired将本身bean引入,然后通过调用自身bean,从而实现使用AOP代理操作。

注入自身bean

@Service
@Slf4j
public class UserService {
    @Autowired
    @Lazy
    private UserService service;
    @Autowired
    UserMapper userMapper;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    UserServiceTwo userServiceTwo;
     @Transactional(propagation=Propagation.REQUIRED)
     public void test1(){
      jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
              "values ('1','a','b','c')");
      System.out.println("tes1执行完");
         service.test2();
      throw new RuntimeException("出错");
     }
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void test2(){
        jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
                "values ('2','aaa','b','c')");
        System.out.println("test2执行完");
    }
}

解决方法2:
通过ApplicationContext引入bean
通过ApplicationContext获取bean,通过bean调用内部方法,就使用了bean的代理类。
注入ApplicationContext

@Service
@Slf4j
public class UserService {
    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    UserMapper userMapper;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    UserServiceTwo userServiceTwo;
     @Transactional(propagation=Propagation.REQUIRED)
     public void test1(){
      jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
              "values ('1','a','b','c')");
      System.out.println("tes1执行完");
         ((UserService)applicationContext.getBean("userService")).test2();
      throw new RuntimeException("出错");
     }
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void test2(){
        jdbcTemplate.execute("insert user (id,userName,passWord,realName) " +
                "values ('2','aaa','b','c')");
        System.out.println("test2执行完");
    }
}

解决方法3: 通过AopContext获取当前类的代理类
通过AopContext获取当前类的代理类,直接通过代理类调用方法
在引导类上添加@EnableAspectJAutoProxy(exposeProxy=true)注解

修改UserService方法
((UserService) AopContext.currentProxy()).test2();

以上就是内部方法调用时,事务不起作用的原因及解决办法。
事务失效 springmvc解决方法连接:https://blog.csdn.net/aosica321/article/details/58039299

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值