事务的传播机制:
- @Transactional(propagation=Propagation.REQUIRED)
如果有事务,那么加入事务,没有的话新建一个(默认情况下)
- @Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
- @Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
- @Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
- @Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
- @Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务。如果其他bean没有声明事务,那就不用事务。
@Transactional(propagation=Propagation.NESTED)
如果当前存在事务,则在嵌套事务内执行,类似数据库事务保存点。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
案例代码
PROPAGATION_REQUIRED
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.REQUIRED)
void methodB() {
}
}
ServiceA.methodA 与 ServiceB.methodB 同时成功,否则都失败。
PROPAGATION_SUPPORTS
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.SUPPORTS)
void methodB() {//依赖调用方法是否事务
}
}
假设当前在事务中,即以事务的形式执行。假设当前不在一个事务中,那么就以非事务的形式执行
PROPAGATION_MANDATORY
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.MANDATORY)
void methodB() {//必须事务执行
}
}
必须在一个事务中执行。也就是说,他仅仅能被一个父事务调用。否则,他就要抛出异常。ServiceA.methodA()必须以事务执行。
PROPAGATION_REQUIRES_NEW
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {//事务A
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.REQUIRES_NEW)
void methodB() {//事务B
}
}
ServiceA.methodA 与ServiceB.methodB是2个独立的事务,互不影响。
当运行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起。ServiceB.methodB会起一个新的事务。等待ServiceB.methodB的事务完毕以后,它才继续运行。
与REQUIRED 的事务差别在于事务的回滚程度。由于ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。假设ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚。ServiceB.methodB是不会回滚的。假设ServiceB.methodB失败回滚,假设他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。
PROPAGATION_NOT_SUPPORTED
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
void methodB() {//非事务方式执行
}
}
当前不支持事务。比方ServiceA.methodA的事务级别是PROPAGATION_REQUIRED 。而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起;而它以非事务的状态执行完,再继续ServiceA.methodA的事务。
PROPAGATION_NEVER
ServiceA {
@Transactional(propagation = Propagation.REQUIRED)
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
@Transactional(propagation = Propagation.NEVER)
void methodB() {// 抛出异常
}
}
不能在事务中执行。如果ServiceA.methodA的事务级别是PROPAGATION_REQUIRED。 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。
嵌套事务不能够提交,它必须通过外层事务来完成提交的动作,外层事务的回滚也会造成内部事务的回滚。
PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。
事务的原理
数据库事务XA模型
- Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
- Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
- Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
事务传播行为就是事务协调器对分支事务的一种控制。
配置方式
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--设置所有匹配的方法,然后设置传播级别和事务隔离-->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!--开启注解的方式-->
<tx:annotation-driven transaction-manager="transactioManager" />