spring事务传播机制


1.事务传播是什么?

	假如有A,B两个方法,方法A有事务,方法B无事务。这时,用调用方法A而方法A会调用方
法B,无事务方法B就会对A产生影响,相反事务方法A也会对B产生影响。这种影响具体是什么
就由两个方法所定义的事务传播类型所决定。

在这里插入图片描述

2.事务传播类型枚举Propagation

阅读源码,和英文注释可知:

事务传播类型有7种
	REQUIRED、
	SUPPORTS、
	MANDATORY、
	REQUIRES_NEW、
	NOT_SUPPORTED、
	NEVER、
	NESTED。

也就是说枚举类Propagation是为了结合@Transactional注解使用而设计的,这个枚举里面定义的事务传播行为类型与TransactionDefinition中定义的事务传播行为类型是对应的,所以在使用@Transactional注解时我们就要使用Propagation枚举类来指定传播行为类型,而不直接使用TransactionDefinition接口里定义的属性。

//Propagation为了结合@Transactional使用而设计的
//而TransactionDefinition接口定义的事务传播行为与Propagation枚举对应,
//使用Propagation类,而不直接使用TransactionDefinition接口
package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
public enum Propagation {
    ...
}

3.七种事务传播行为,案例理解

首先我们为事务传播设计一个案例,比如我要录入一个商品,加入商品的图片。

//业务层中
public void goods(Goods a){
	insertGoods(a);
}
public void img(Img b){
	insertImg(b);
}
//测试层中
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

①REQUIRED(Spring默认传播事务)

 Support a current transaction, create a new one if none exists.
 支持当前事务,如果没有事务就创建一个新事务。

情况1

//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

没有任何数据被录入,假如testA中没有事务,那么就创建一个新的事务,由于调用了testB,所以沿用当前事务,抛出异常时,回滚当前事务,没有任何数据被录入。

情况2

//测试层中
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

商品本身被录入,testA无事务,所有会被忽略,不会出现回滚,而testB中的事务,会因为抛出异常而被回滚。

②SUPPORTS

Support a current transaction, throw an exception if none exists.
支持当前事务,如果不存在则抛出异常(无事务就以无事务的方式处理)
//测试层中
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.SUPPORTS)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

商品a和图片b1被录入,testA中无事务所以直接插入,testB延续A的无事务状态,遇见异常后b2不执行,所以只录入了商品a和图片b1.

③MANDATORY

Support a current transaction, throw an exception if none exists.
支持当前事务,如果不存在则抛出异常
//测试层中
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.MANDATORY)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

只有商品a被录入,testA无事务所有被录入,而testB中由于没有事务,但是遇见了异常就会全部回滚。

④REQUIRES_NEW

Create a new transaction, and suspend the current transaction if one exists.
创建一个事务,如果不存在,就挂起该事务
//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
    new throw Exception;     //发生异常抛出
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testB(){
    img(b1);  //添加图片b1
    img(b2);  //添加图片b2
}

只存储了图片b1和b2,在执行testB会开启一个新事务,而testA发生的异常会回滚testA中的数据,所以商品a没有存储。
如果将testA和testB都设置成REQUIRED,那么所有数据都会回滚不会存储,因为他们都是一个事务下的,数据都会回滚

⑤NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists.
以非事务方式执行,如果当前事务存在,则挂起当前事务。
//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception;     //发生异常抛出
    img(b2);  //添加图片b2
}

只有图片b1录入,testA执行,当testB执行时,将testA事务挂起,直接录入了图片b1,但是抛出异常b2未执行。而testA事务出现异常,开始回滚。

⑥NEVER

Execute non-transactionally, throw an exception if a transaction exists	
不使用事务,如果当前事务存在,则抛出异常
很容易理解,就是我这个方法不使用事务,并且调用我的方法也不允许有事务,如果调用我的方法有事务则我直接抛出异常。
//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
}

@Transactional(propagation = Propagation.NEVER)
public void testB(){
    img(b1);  //添加图片b1
    img(b2);  //添加图片b2
}

没有任何数据录入,由于testA有事务,调用了没有不允许使用事务的testB,直接抛出异常。

⑦NESTED

Execute within a nested transaction if a current transaction exists
如果当前事物存在,则嵌套在事务中执行。否则REQUIRED的操作一样(开启一个事务)

情况1

//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    testB();   //调用testB
    new throw Exception; //抛出异常
}

@Transactional(propagation = Propagation.NESTED)
public void testB(){
    img(b1);  //添加图片b1
    img(b2);  //添加图片b2
}

数据都不会录入,因为在testMain发生异常时,父事务回滚则子事务也跟着回滚了

情况2

//测试层中
@Transactional(propagation = Propagation.REQUIRED)
public void testA(){
    goods(a);  //添加商品a
    try{
        testB();    //调用testB
    }catch(Exception e){

    }
    goods(a2);   //调用testB
}

@Transactional(propagation = Propagation.NESTED)
public void testB(){
    img(b1);  //添加图片b1
    new throw Exception; //抛出异常
    img(b2);  //添加图片b2
}

只有商品a和a2录入,因为testA事务捕获了异常,testA会正常执行,而testB嵌套中抛出异常会只回滚testB。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小小狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值