什么是传播行为?
默认情况下,只有一个事务,所有的修改操作都在一个事务里面,要么一起提交,要么一起回滚,这没什么问题。但要是有2个或者2个事务以上该如何解决呢?
既然是传播,那么至少要有2个东西,才可以传播,我传给你或者你传给我,才叫传播,单体不存在传播这个行为;
事务传播行为,指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。比如说,A事务方法调用了B事务方法,B是继续在调用者A的事务中运行呢?还是为自己另开一个新事物运行? 这就是由B的事务传播行为决定的。
spring事务传播行为一共有7种:(前言: 当前事务指的是调用者自带的事务,A调用B,那么A就是当前事务)
- REQUIRED (默认传播行为),支持当前事务,如果当前没有事务,就新建一个事务,这个当前事务指的是上一个方法的事务,是别人传递过去的,类似于重入锁,A方法和B方法都有事务,A方法调用B方法,A的事务会传递给B,使它们共用同一个事务,我起了个名字叫做重入事务
- SUPPORTS 如果存在一个事务,支持当前事务,如果没有事务,则非事务执行,
- REQUIRES_NEW 开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起
- MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
- NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务
- NEVER 总是非事务地执行,不加入任何事务;
- NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按 REQUIRED 属性执行。
大体讲完了, 接下来, 我们一个个地细化讲解,为了方便大家理解,下面的例子会把里面的AB方法以及其他概念做一些转化;具体关系如下:
A ----------------> 哥哥
B ----------------> 我
执行代码 ------> 读书
事务-------------> 吃苹果
挂起事务 ------> 暂停吃苹果
抛异常 ----- ---> 妈妈发脾气
1、REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。很好理解,不管有几个事务存在,都合并成一个事务来处理,只要有一个事务抛出异常,所有事务都会回滚;
大白话:哥哥和我,我们两个人每人都有一个苹果,最终我们的苹果会合并成一个苹果一起吃;
举例代码
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertB(){
- // do something
- }
2、SUPPORTS
如果存在一个事务,支持当前事务,如果没有事务,则非事务执行。
大白话:如果哥哥有一个苹果,我就吃哥哥的苹果,如果哥哥没有苹果,那我也没得吃;
使用举例
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.SUPPORTS)
- public void insertB(){
- // do something
- }
3、REQUIRES_NEW
开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起,
大白话:不管怎样,我都会得到一个新的苹果,如果哥哥正在吃苹果,那么他吃苹果的动作会先暂停,等我吃完之后哥哥在继续吃;
使用举例
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.REQUIRES_NEW)
- public void insertB(){
- // do something
- }
4、MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
大白话:如果哥哥有一个苹果,那么我也吃他的苹果,如果哥哥没有苹果,妈妈就会发脾气;
使用举例--第一种情况,没有当前事务,controller 直接调用方法B
- // 方法B
- @Transactional(propagation = Propagation.MANDATORY)
- public void insertB(){
- // do something
- }
第二种情况,有当前事务
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.MANDATORY)
- public void insertB(){
- // do something
- }
5、NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务
大白话:我总是不吃苹果,如果哥哥正在吃苹果,遇到我正在读书,哥哥会暂停吃苹果这个行为,待我读书读完后,哥哥就会继续吃苹果
代码举例
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NOT_SUPPORTED)
- public void insertB(){
- // do something
- }
6、NEVER
总是非事务地执行,不加入任何事务;如果存在一个活动事务,则抛出异常。
大白话:我总是不吃苹果,如果哥哥有苹果,那妈妈就会发脾气
代码举例,第一种情况,没有任何事务
- // 方法A
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NEVER)
- public void insertB(){
- // do something
- }
第一种情况,A有事务 ,这种情况会抛异常: IllegalTransactionStateException
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NEVER)
- public void insertB(){
- // do something
- }
7、NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按 REQUIRED 属性执行。
大白话:如果哥哥吃苹果吃出毛病了(代码抛异常了),那我和哥哥都会回到原点(回滚),如果我吃苹果吃出毛病了(代码抛异常了),那就只有我会回到原点(回滚);
代码举例,第一种情况,A方法抛出异常,A和B都会回滚
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
- // 抛出异常
- throw new Exception();
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NESTED)
- public void insertB(){
- // do something
- }
第二种情况,B方法抛出异常,只回滚B事务;
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- insertB();
- // do something
-
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NESTED)
- public void insertB(){
- // do something
- throw new Exception();
- }
当我们使用上面第二种情况的代码的时候,其实内部的伪代码其实是这样的
- // 方法A
- @Transactional(propagation = Propagation.REQUIRED)
- public void insertA(){
- // do something
- try{
- insertB();
- } catch (Exception e){
- e.printStackTrace();
- }
- // do something
- }
-
- // 方法B
- @Transactional(propagation = Propagation.NESTED)
- public void insertB(){
- // do something
- throw new Exception();
- }
到这里事务传播行为就介绍完了,如果还是不懂,那就得请个脑科大夫看看了!!