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。