1. Spring支持编程式事务管理TransactionTemplate
和声明式事务管理@Transactional
两种方式
和编程式事务相比,声明式事务唯一不足地方是最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等(比如使用
AopContext.currentProxy()
)。
2. @Transactional
可通过AopContext.currentProxy()
解决在同一个类中,非事务方法A调用事务方法B,事务失效
B方法被A调用,对B方法的切入失效,但加上 AopContext.currentProxy() 创建了代理类,在代理类中调用该方法前后进行切入。对于B方法 proxy.B,执行的过程是先记录日志后调用方法体,但在A方法 proxyA中调用只能对A进行增强,A里面调用B使用的是对象.B(),而不是 $proxy.B(),所以对B的切入无效。
注:AopContext.currentProxy()使用了ThreadLocal保存了代理对象,因此
AopContext.currentProxy().B()就能解决。
public class Demo {
public void methodA () {
...
// 获取当前代理类,保证同一个类中非事务方法调用事务方法时事务生效
((Demo) AopContext.currentProxy()).methodA();
...
}
@Transactional(rollbackFor = Exception.class)
public void methodB () {
...
}
}
- 使用
@Transactional
声明式事务
是否在同一个类 | 调用 | 事务是否生效 |
---|---|---|
在不同类中 | 事务方法A调用非事务方法B | 事务生效 |
在不同类中 | 非事务方法A调用事务方法B | 事务生效 |
在同一个类中 | 事务方法A调用非事务方法B | 事务具有传播性,事务生效 |
在同一个类中 | 非事务方法A调用事务方法B | 事务失效 |
转载:https://www.jianshu.com/p/2ab568e7aaf7
3. 编程式事务TransactionTemplate用法
public class Demo {
@Resource
private TransactionTemplate transactionTemplate;
public void methodA () {
...
// 指定事务传播性(可不设置,默认是`PROPAGATION_REQUIRED`)
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 指定事务隔离级别(可不设置,默认是`ISOLATION_DEFAULT`,同数据库隔离级别)
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
transactionTemplate.execute(transactionStatus -> {
methodB();
return Boolean.TRUE;
});
...
}
public void methodB () {
...
}
}
- 事务传播行为
1. TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3. TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
5. TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
6. TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
7. TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
- 事务的隔离级别
1. @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,
不可重复读) 基本不使用
2. @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
3. @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
4. @Transactional(isolation = Isolation.SERIALIZABLE):串行化