Spring事务管理
Spring抽象了事务管理策略模型,为处理不同实现机制的事务提供了统一的编程模型。
核心模型
- Spring事务管理抽象分为命令时事务管理模型(PlatformTransactionManager)和响应式事务管理模型(ReactiveTransactionManager),PlatformTransactionManager为命令式应用事务抽象,ReactiveTransactionManager为响应式应用(Reactive Application)事务抽象
- TransactionDefinition 定义了事务的传播方式、隔离级别、超时、回滚、只读事务
- TransactionStatus(ReactiveTransaction) 定义了事务的执行以及事务的状态
事务管理方式分类
声明式事务管理
声明式事务管理主要通过切面代理和metadata(注解和xml配置)配置来实现,TransactionInterceptor根据当前的编程语言模型( imperative 、 reactive)来选择合适的事务策略模型。事务的核心注解**@Transactional**在命令式编程模型中,只能处理当前线程范围的事务,不能把事务传递到新线程,在响应式编程模型中,也只能处理当前contenxt(Reactor context)的事务
注解驱动事务配置(TransactionManager)
mode
- proxy 使用spring aop framwork来代理目标对象的方法调用,目标对象的方法只能是公共方法
- aspectj 采用spring aspectj 事务切面,通过修改字节码方式织入事务,可以应用于任何类型的方法调用
proxy-target-class
该属性是在mode为proxy配置时,指定事务注解是基于具体类的代理还是基于接口代理
注意事项
- Spring自身框架中,@Transactional仅支持公共方法,如果需要在非公共方法上使用事务注解,使用aspectj模式
- 由于java中注解是不能从接口继承的,所以,最好把注解使用到具体类或具体类的方法上
- 代理模式下,方法的调用会被代理拦截,因此,同类中的方法调用即使被调用方法有事务注解,也不会使用事务
- 方法事务设置优先于类事务设置
- Spring默认只对未检查的RuntimeException进行回滚,如要Exception及子类进行回滚,需要进行配置
事务注解配置(@Transactional)
Spring事务注解的关键配置包括传播类型(propagation)、隔离级别(isolation)、 读写(read-only)、 超时(timeout)、回滚(rollback-for/no-rollback-for)。事务分为逻辑事务和物理事务,不同的传播类型将影响内部事务设置(isolation、read-only、timeout)
事务传播类型
PROPAGATION_REQUIRED(一个物理事务,多个逻辑事务)
- 强制开启一个物理事务, 内部每个方法将开启一个逻辑事务,每个逻辑事务可以独立的设置rollback-only status,由于只有一个物理事务,内部事务的rollbakc-only设置将影响外部事务的提交
- 如果内部事务设置了rollback-only,但是外部事务又没有决定回滚自己,将会出现UnexpectedRollbackException异常
public class A{
@Transactional
public void updataA(Integer id){
return jdbcTemplate.update("update store set num=num-1 where bookid=?",id);
}
@Transactional(rollbackFor = Exception.class)
public void updateB(Integer id,Double price) throws Exception {
int update = jdbcTemplate.update("update book set price=price+? where id=?", price, id);
throw new Exception("test");
}
}
public class B{
private A a;
@Transactional
public void update() throws Throwable{
a.updateA(1);
//int a=1/0;
a.updateB(1,50.0);
}
}
- 默认情况下内部事务的隔离级别、timeout、 read-only设置将被忽略,如果内部事务需要单独设置,需要在事务管理(Transaction Manager)的配置中开启validateExistingTransactions
PROPAGATION_REQUIRES_NEW(多个物理事务)
每个使用了@Transactional注解都使用独立的物理事务
PROPAGATION_NESTED(一个物理事务,多个savepoint)
一个物理事务,每个内部事务有一个savepoint,因此,内部事务的回滚,不影整个事务,同时由于savepoint 映射为jdbc的savepoint,因此只适用于jdbc 事务类型
编程事务
- 命令式语言使用TransactionTemplate ,响应式语言使用 TransactionalOperator
- 直接实现TransactionManager