hi ,大家好,继续为大家带来Spring事务传播机制的相关知识
文章目录
- 🤗1.事务传播机制是什么
- 🤗2.事务传播机制作用
- 🤗3.事务传播机制
🤗1.事务传播机制是什么
定义了多个包含了事务的⽅法,相互调⽤时,事务是如何在这些⽅法间进⾏传递的
🤗2.事务传播机制作用
事务隔离级别是保证多个并发事务执⾏的可控性的(稳定性的),而事务传播机制是保证⼀个事务在多个调用方法间的可控性的(稳定性的)
上面的图片很好的解释了事务传播机制和事务隔离级别的流程
🤗3.事务传播机制
Spring事务传播机制定义了在多个事务方法相互调用时,不同事务方法间事务处理的行为方式。Spring框架提供了7种不同的事务传播行为方式,分别是:
- REQUIRED:默认的传播行为,如果当前存在事务,则加入该事务,否则创建一个新事务。
这个来通俗的解释一下,如果当前方法没有开启事务,就会创建一个新的事务,如果存在事务就会加入该事务
我们在用代码验证一下
因为此时的级别默认是required,所以应该是一个大事务,有一个有异常 ,其余的也就添加失败
可以从数据库中看到,并未添加数据
- SUPPORTS:如果当前存在事务,则加入该事务,否则不使用事务。
如果A 没有开启事务,那么就以非事务的方式运行,后面的方法看到该调用链没有事务就也会摆烂,因此即使报了异常,也继续添加,
看代码
3 MANDATORY:当前方法必须在事务中执行,存在事务,就会加入该事务,如果不存在事务,则抛出异常。
4.REQUIRES_NEW:表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。
5.NOT_SUPPORTED:以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起
6.NEVER:当前方法不能在事务中执行,如果存在事务,则抛出异常。
可以清楚的看到没有插入
控制台连受影响的行数都没有打印,直接抛出异常
这个NESTED比较绕😭,我们一起努力,冲冲冲!😜
7.NESTED:创建一个嵌套事务,如果当前存在事务,则将该事务作为嵌套事务的父事务,如果父事务提交,则嵌套事务会提交,否则回滚。
如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。
执行流程
当没有事务,创建事务,后续方法会生成嵌套事务,并且有一个保存点,一旦该事务出现问题,就会回滚到上一个事务保存点,不会影响其他事务的执行
package com.example.demo.controller;import com.example.demo.model.Userinfo;
import com.example.demo.service.UserService;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.pattern.PathPattern;//测试类@RestController@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/add")@Transactional(propagation = Propagation.REQUIRED)public int add(){Userinfo userinfo=new Userinfo();userinfo.setUsername("老七");userinfo.setPassword("123");int result= userService.add(userinfo);System.out.println("受影响的行数是"+result);userService.insert(userinfo);return result;}
}
package com.example.demo.service;import com.example.demo.mapper.UserMapper;
import com.example.demo.model.Userinfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactional(propagation = Propagation.NESTED)public int add(Userinfo userinfo){int result=userMapper.add(userinfo);System.out.println("受影响的行数"+result);return result;}@Transactional(propagation = Propagation.NESTED)public int insert(Userinfo userinfo){int result=userMapper.add(userinfo);System.out.println("受影响的行数"+result);int num=10/0;return result;}
}
数据库是啥也没插入的,为啥呢?不是说会回滚到上一个事务保存点吗?所以应该插入一条,为啥一条也没有
因为:
第三个出了问题,那么创建事务的作为调用方,一定可以感知到异常,那么整个事务就会回滚,所以一条都不会插入
所以某个方法报异常不要让总的调用者感知到,就不会全部回滚,那么可以采用如下方式
修改这里的代码,让该方法感知到异常即可,不让总方法感知到,那么就会执行回滚操作,回滚到上一个事务保存点,所以只会插入一条数据
在写这个例子的时候,我们特意修改,不在add方法里面调用insert方法,而是在userController中调用,为什么呢?
🤗🤗🤗因为NESTED嵌套NESTED的时候,上一个NESTED保存点设置不上,这两个保存点会进行合并,合并成一个临时任务,那么一个挂掉,两个都挂了,所以在总的调用方法中调用它,才能有效果
再举一个例子:
公司雇了一个清洁工A,清洁工自己有又雇了一个清洁工B,当清洁B干了坏事,那么公司就会把A和B同时开除,当公司雇了两个清洁工,其中一个清洁工出了问题,就开掉出问题的那个就好,没出问题的留下~
这个例子就对应了代码的执行过程~
今天就讲到这里,我们下期再见,886!