NOTE
2.48 传播行为
1. 是什么 事务传播行为是Spring对数据库事务的增强特性,用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法时事务如何传播。 一般我们的事务都是写在service方法上,调用dao的方法时生效。 但是如果service A的方法调用service B的方法这种情况该怎么定义呢? 1.1.
这是历史学习笔记,可能存在过时或不完整的理解。
1. 是什么
事务传播行为是Spring对数据库事务的增强特性,用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法时事务如何传播。
一般我们的事务都是写在service方法上,调用dao的方法时生效。 但是如果service A的方法调用service B的方法这种情况该怎么定义呢?
1.1. 传播行为有哪些
1.1.1. PROPAGATION_REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。如果有事务的话就加入当前事务。这是最常见的选择。
- ServiceA
@Transactional(PROPAGATION_REQUIRED)
methodA
{
doSomething();
ServiceB.methodB();
}
- ServiceB
methodB
{
doSomethingToo();
}
这个例子中methodA和methodB运行在同一个事务中,只要一个地方有异常那么直接回滚
1.1.1.1. 注意
如果ServiceA的methodA是如下这样的:
methodA
{
doSomething();
try
{
ServiceB.methodB();
}catch (Exception e)
....
}
那么当methodB抛出异常时这个事务首先标记为需要回滚,但是回到methodA时这个异常又会被捕获。就会造成要回滚却又回滚不了的情景。 抛出transaction has been marked as rollback only异常 解决办法是把methodB放在PROPAGATION_REQUIRES_NEW中
1.1.2. PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
1.1.3. PROPAGATION_MANDATORY
支持当前事务,如果当前没有事务,就抛出异常。
1.1.4. PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。 如果当前没有事务,就新建一个事务。如果有事务的话那么新建一个事务,在那个事务中执行
- ServiceA
@Transactional(PROPAGATION_REQUIRED)
methodA
{
doSomething();
ServiceB.methodB();
}
-ServiceB
@Transactional(PROPAGATION_REQUIRES_NEW)
methodB
{
doSomethingToo();
}
如上例子methodA运行在一个事务中,调用methodB时methodB会新开一个事务运行,methodB抛出异常只回滚methodB,methodA调用methodB之后的地方抛出异常只会回滚methodA
1.1.5. PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
1.1.6. PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
1.2. 注意
1.2.1. 同一个类创建一个事务代理类
- ServiceA
@Transactional(PROPAGATION_REQUIRED)
methodA
{
doSomething();
methodA2();
}
@Transactional(PROPAGATION_REQUIRED_NEW)
methodA2
{
doSomething();
ServiceB.methodB();
}
如上例子的methodA2的注解不会生效,因为动态代理只会为同一个类创建一个事务代理类
1.2.2. Transaction already marked as rollback
- ServiceA
@Transactional(PROPAGATION_REQUIRED)
methodA
{
doSomething();
try
{
serviceB.methodB();
}catch (Exception e)
{
e.printStackTrance();
}
}
- ServiceB
@Transactional(PROPAGATION_REQUIRED)
methodB
{
throw new RuntimeExecption("serviceB methodB exp..");
}
如上的代码会抛出异常Transaction already marked as rollback,原因在于ServiceA.methodA首先开启了一个事务,由于ServiceB.methodB的传播行为是PROPAGATION_REQUIRED,那么他不会创建新的事务,而是直接加入ServiceA.methodA的事务中。
ServiceB.methodB抛出了一个异常,这个事务会标记为待回滚状态,但是ServiceA.methodA又捕获了这个异常没有对外抛出,那么这就矛盾了。
明明标记为待回滚,但是有没有异常抛出,这到底回滚还是不会滚啊