使用@Transactional有一些需要注意的地方:
- Spring默认情况下会对(RuntimeException)及其子类来进行回滚,在遇见Exception及其子类的时候则不会进行回滚操作
- @Transactional注解应该只被应用到public方法上,这是由Spring AOP的本质决定的
@Transactional注解要生效的话,需配置@EnableTransactionManagement,不过如果是使用SpringBoot的话,就可以不需要了:
@SpringBootApplication
@EnableTransactionManagement // 这行注解其实可以不需要,在TransactionAutoConfiguration自动配置类里已经带有此注解
public class SpringTransactionalApplication {
public static void main(String[] args) {
SpringApplication.run(SpringTransactionalApplication.class, args);
}
}
TransactionAutoConfiguration自动配置类定义了很多与事务处理相关的bean,其中与@Transactional注解息息相关的是这个类TransactionInterceptor.
每个带有@Transactional注解的方法都会创建一个切面,所有的事务处理逻辑就是由这个切面完成的,这个切面的具体实现就是TransactionInterceptor类.
注意,这个TransactionInterceptor是个单例对象,所有带有@Transactional注解的方法都会经由此对象代理:
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
// ......
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
// ......
}
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// ......
// 这里TransactionAttributeSource对象保存了应用内所有方法上的@Transactional注解属性信息,利用Map来保存,其中
// key由目标方法method对象+目标类targetClass对象组成,所以通过method+targetClass就能唯一找到目标方法上的@Transactional注解属性信息
TransactionAttributeSource tas = getTransactionAttributeSource();
// 这个TransactionAttribute对象就保存了目标方法@Transactional注解所有的属性配置,如timeout,propagation,readOnly等等,
// 后续就利用这些属性完成对应的操作
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// ......
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 这里最终会调用到目标方法
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
// 目标方法抛出了异常,根据@Transactional注解属性配置决定是否需要回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
// ......
// 目标方法正常执行完成,提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
}
@Transactional注解属性含义:
- value:可选的限定描述符,指定使用的事务管理器
- propagation:可选的事务传播行为设置
- isolation: 可选的事务隔离级别设置
- readOnly:读写或只读事务,默认读写
- timeout:事务超时时间设置
- rollbackFor:导致事务回滚的异常类数组
- rollbackForClassName:导致事务回滚的异常类名字数组
- oRollbackFor:不会导致事务回滚的异常类数组
- noRollbackForClassName:不会导致事务回滚的异常类名字数组
propagation各属性值含义:
- Propagation.REQUIRED:如果有事务,那么加入事务,没有的话新创建一个
- Propagation.NOT_SUPPORTED:这个方法不开启事务
- Propagation.REQUIREDS_NEW:不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
- Propagation.MANDATORY:必须在一个已有的事务中执行,否则抛出异常
- Propagation.NEVER:不能在一个事务中执行,就是当前必须没有事务,否则抛出异常
- Propagation.SUPPORTS:若当前存在事务,则在事务中运行.否则以非事务形式运行
- Propagation.NESTED:如果当前存在事务,则运行在一个嵌套的事务中,如果当前没有事务,则按照REQUIRED属性执行.它只对DataSourceTransactionManager事务管理器起效
关于Spring如何处理该属性参见AbstractPlatformTransactionManager类的getTransaction方法.
isolation各属性值含义:
- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据.该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别.比如PostreSQL实际上并没有此级别.
- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据.该级别可以防止脏读,这也是大多数情况下的推荐值.
- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同.该级别可以防止脏读和不可重复读.
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读.但是这将严重影响程序的性能,通常情况下也不会用到该级别.