概述:
有时候我们会遇到一个方法套另一个方法的情况如下:
Java代码:
//@Transactional
methodA(){
doSomeThingA();
methodB();
doSomeThingB();
}
//@Transactional
methodB(){
……
}
Java代码:
main(){
methodA();
}
事务的传播特性指在事务方法被另一个事务方法调用的时候如何定义事务流程。
那么理解了这句话我们先看下事务的传播类型如下:
/**
* Support a current transaction; create a new one if none exists.
如果当前事务不存在,重新创建一个事务,否则进入当前事务
int PROPAGATION_REQUIRED = 0;
/**
* Support a current transaction; execute non-transactionally if none exists.
当前事务不存在,执行无事务运行,否则进入当前事务
int PROPAGATION_SUPPORTS = 1;
/**
* Support a current transaction; throw an exception if no current transaction
当前事务不存在抛异常,否则进入当前事务
int PROPAGATION_MANDATORY = 2;
/**
* Create a new transaction, suspending the current transaction if one exists.
如果当前事务存在挂起当前事务,重新创建一个新事务,等待新事务执行完毕,之前挂起的事务继续运行,两者事务无必然联系
int PROPAGATION_REQUIRES_NEW = 3;
/**
* Do not support a current transaction; rather always execute non-transactionally.
*/
不支持事务运行
int PROPAGATION_NOT_SUPPORTED = 4;
/**
* Do not support a current transaction; throw an exception if a current transaction
* exists.
*/
当前事务存在,抛异常,否则无事务运行
int PROPAGATION_NEVER = 5;
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
* feature in EJB.
内嵌事务这里解释一下:, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back
int PROPAGATION_NESTED = 6;
那我要说的重点来了,如果有一个情况是这样的:
如果一个方法既有自己的事务方法也包含子事务service方法,类似下面这样
@Transactional
methodA(){
doSomeThingA();
methodB();
doSomeThingB();
}
// @Transactional ===> PROPAGATION_NESTED
methodB(){
……这里可能好几个DAO
}
//
doSomeThingA(DAO操作){
……
}
//
doSomeThingB(DAO操作){
……
}
按照前面对嵌套事务的描述那么可能会有几种情况:
1 doSomeThingB 方法报错,整个连带事务回滚
2 methodB内部报错,不会引起外层methodA 方法回滚
所以如果需要整个事务回滚的话尽量避免嵌套事务,除非特殊情况
那么如果需要保持多个方法一致性的业务如何处理?
很简单写在一个方法里边就可以了,因为SPRING嵌套事务无法保证一致性
另外在说一个细节,在一个方法业务没有数据库修改的情况下,推荐加上只读事务(read-only),这样编译器会优化读事务处理,因为我们都知道事务的重量级会直接导致并发效率的下降。