除了使用注解这个声明式事务来管理事务外,还有编程式事务管理方式,通过 TransactionTemplate 或者 TransactionManager 手动管理事务,实际应用中很少使用
调用 TransactionTemplate 的 execute 方法来执行事务,传入一个 TransactionCallbackWithoutResult 对象
@Resource
private TransactionTemplate transactionTemplate;
public void test() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
// ....
} catch (Exception e){
//回滚
transactionStatus.setRollbackOnly();
}
}
});
}
还有一个调用 TransactionManager 的 getTransaction 方法,这里就不写了
一共五种隔离级别,使用 isolation(隔离)属性来配置
四种隔离级别与MySQL的隔离级别相同,分别是读未执行,读已执行,不可重复读,串行化
另外一种是默认隔离级别,使用后端数据库默认的隔离级别
指服务层的事务方法之间互相调用时会发生什么
使用propagation(交易)来配置传播行为,一共有七种传播行为
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
......
}
Spring 为了方便使用,定义了一个枚举类:Propagation,虽然不知道这个枚举类方便在哪里
package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
public enum Propagation {
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
NEVER(TransactionDefinition.PROPAGATION_NEVER),
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
支持外围事务的情况:
1,PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,创建一个新事务,这个是默认的,并且也使用的最多
举个例子,当两个方法都用这个传播行为,a 调用 b,此时b中的行为加入a,形成同一个事务,此时b中错误出现回滚a也跟这回滚;a如果是一个普通方法,调用事务方法b,此时b生成一个新事务干自己的事情
2,PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
3,PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
不支持外围事务:
1,PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起
听说过线程挂起听说过事务挂起吗?当事务创建时,就会被绑定到一个线程上。该线程会伴随着事务整个生命周期,直到事务提交、回滚或挂起(临时解绑)。线程和事务的关系是1:1,当线程绑定了一个事务后,其他事务不可以再绑定该线程,反之亦然
了解事务和线程的关系,也很容易理解事务挂起。对事务的配置在Spring内部会被封装资源(Resource),线程绑定了事务,自然也绑定了事务相关的资源。挂起事务时,把这些资源取出临时存储,等待执行完成后,把之前临时存储的资源重新绑定到该线程上
这种情形下,事务a调用事务b,a在b执行完后发生异常,b不会回滚,但是如果b抛出异常,a会回滚
2,PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起
3,PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常
其他情况:
PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,创建一个事务。如果 b 回滚的话,a 也会回滚
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒,默认值为-1,这表示事务的超时时间取决于底层事务系统或者没有超时时间
若同一类中的其他没有 @Transactional 注解的方法内部调用有 @Transactional 注解的方法,有@Transactional 注解的方法的事务会失效。
这是由于Spring AOP代理的原因造成的,因为只有当 @Transactional 注解的方法在类以外被调用的时候,Spring 事务管理才生效。