事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是经过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 所以在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中作相关的事务规则声明,另外一种是基于@Transactional 注解的方式。注释配置是目前流行的使用方式,所以本文将着重介绍基于@Transactional 注解的事务管理。html
正确的设置@Transactional 的 propagation 属性
须要注意下面三种 propagation 能够不启动事务。原本指望目标方法进行事务管理,但如果错误的配置这三种 propagation,事务将不会发生回滚。java
- TransactionDefinition.PROPAGATION_SUPPORTS:若是当前存在事务,则加入该事务;若是当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,若是当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,若是当前存在事务,则抛出异常。
正确的设置@Transactional 的 rollbackFor 属性
默认状况下,若是在事务中抛出了未检查异常(继承自 RuntimeException 的异常)或者 Error,则 Spring 将回滚事务;除此以外,Spring 不会回滚事务。spring
若是在事务中抛出其余类型的异常,并指望 Spring 可以回滚事务,能够指定 rollbackFor。例:编程
@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class)ui
经过分析 Spring 源码能够知道,若在目标方法中抛出的异常是 rollbackFor 指定的异常的子类,事务一样会回滚。this
@Transactional 只能应用到 public 方法才有效
只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是由于在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行先后进行拦截以前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 经过这个类获取表 1. @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。编码
protected TransactionAttribute computeTransactionAttribute(Method method,
Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;}
这个方法会检查目标方法的修饰符是否是 public,若不是 public,就不会获取@Transactional 的属性配置信息,最终会形成不会用 TransactionInterceptor 来拦截该目标方法进行事务管理。spa
避免 Spring 的 AOP 的自调用问题
在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会形成自调用问题。若同一类中的其余没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。代理
最后这两个问题,使用 AspectJ 取代 Spring AOP 代理可解决。code
原文:https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html