Spring 事务传播

(1)事物的7个传播行为:

org.springframework.transaction.annotation中的枚举类Propagation有以下七个值:

Propagation.REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
Propagation.SUPPORTS-- 支持当前事务,如果当前没有事务,就以非事务方式执行。 
Propagation.MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 
Propagation.REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 
Propagation.NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
Propagation.NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 
Propagation.NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。

在声明事务@Transactional(propagation=Propagation.REQUIRES)是可以指定事务类型。Propagation.REQUIRES是spring默认事务类型。

(2)当在主ServiceA中执行方法doSomeA(),中间调用ServiceB中doSomeB(),在默认事务(Propagation.REQUIRES)的情况下经过测试结果如下:

//serviceA.doSomeA,插入数据1、4

@Transactional
public void doSomeA() {
    myMapper.insertTestDb("1");
    serviceB.doSomeB();
    //int throwExcept = Integer.valueOf("err");//异常点
    myMapper.insertTestDb("4");
}

//serviceB.doSomeB,插入数据2、3

@Transactional
public String doSomeB(){
    myMapper.insertTestDb("2");
    myMapper.insertTestDb("3");
}
方法
执行顺序方法位置db操作
1外层serviceA.doSomeAinsert1
2内层serviceB.doSomeBinsert2
3内层serviceB.doSomeBinsert3
4外层serviceA.doSomeAinsert4

 

在不同的地方设置异常操作int throwExcept = Integer.valueOf("err");

执行顺序方法   
1serviceA.doSomeAinsert1 
2 异常点1
3serviceB.doSomeB 异常点2
4insert2 
5 异常点3
6insert3 
7 异常点4
8serviceA.doSomeA 异常点5
9insert4 
10 异常点6

 

以下是在不同位置出现异常的db插入结果,可以看出在serviceB.doSomeB内部的事务与外部的serviceA.doSomeA操作上是一个原子,可以类似的看作一个事务的执行来判断。

这种内外层都有事务的情况和只有外层事务的效果应该是一致的。

 

PROPAGATION.REQUIRED内外都有事务抛出异常(不进行异常处理)
正常执行异常点1异常点2异常点3异常点4异常点5异常点6
1未插入未插入未插入未插入未插入未插入
2未插入未插入未插入未插入未插入未插入
3未插入未插入未插入未插入未插入未插入
4未插入未插入未插入未插入未插入未插入
       
内外都有事务异常所在方法内捕获(try...catch...)
正常执行异常点1异常点2异常点3异常点4异常点5异常点6
1111111
2未插入未插入2222
3未插入未插入未插入333
4未插入444未插入4
       
内外都有事务捕获异常后手动回滚(RollbackOnly)
正常执行异常点1异常点2异常点3异常点4异常点5异常点6
1未插入未插入未插入未插入未插入未插入
2未插入未插入未插入未插入未插入未插入
3未插入未插入未插入未插入未插入未插入
4未插入未插入未插入未插入未插入未插入

 

(3)Propagation.REQUIRES_NEW

当serviceB.doSomeB设置为@Transactional(propagation=Propagation.REQUIRES_NEW)时,外层serviceA.doSomeA的事务在执行到serviceB.doSomeB时会A中事务被挂起,等doSomeB执行完了,结果会立即插入db中,不会等待doSomeA执行结束。因此doSomeA中出现异常也不会导致doSomeB中回滚。

如果doSomeB中抛出异常,在doSomeB内部被捕获了,然后手动进行回滚,影响范围也只局限于doSomeB中,不会导致doSomeA中事务被回滚。

因此,当doSomeA与doSomeB中操作不需要作为一个原子时,可以独立起一个事务,做到互不影响。

Spring事务传播是指在多个具有事务控制的service相互调用时所形成的复杂事务边界控制。Spring提供了七种事务传播行为,分别是: 1. REQUIRED(默认):表示当前方法必须在一个具有事务的上下文中运行,如果客户端有事务在进行,那么被调用端将在该事务中运行,否则重新开启一个事务。如果被调用端发生异常,调用端和被调用端事务都将回滚。 2. SUPPORTS:表示当前方法可以在一个具有事务的上下文中运行,也可以在没有事务的上下文中运行。 3. MANDATORY:表示当前方法必须在一个具有事务的上下文中运行,如果没有事务则抛出异常。 4. REQUIRES_NEW:表示当前方法必须运行在它自己的事务中。一个新的事务将启动,如果有现有的事务在运行,则该方法被挂起,直到新的事务提交或回滚才恢复执行。 5. NOT_SUPPORTED:表示当前方法不应该运行在一个事务中,如果有事务在运行,则将该事务挂起,直到方法执行完毕。 6. NEVER:表示当前方法不应该运行在一个事务中,如果有事务在运行,则抛出异常。 7. NESTED:表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务存在,并且外层事务回滚,那么内层事务必须回滚,反之,内层事务不影响外层事务。如果封装事务不存在,则与REQUIRED相同。 这些事务传播行为可以根据具体的业务需求来选择,以实现正确的事务控制。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值