事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是经过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 所以在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中作相关的事务规则声明,另外一种是基于@Transactional 注解的方式。注释配置是目前流行的使用方式,所以本文将着重介绍基于@Transactional 注解的事务管理。html
第一步:在 xml 配置文件中添加如清单 1 的事务配置信息。除了用配置文件的方式,@EnableTransactionManagement 注解也能够启用事务管理功能。这里以简单的 DataSourceTransactionManager 为例。java
清单 1. 在 xml 配置中的事务配置信息spring
<tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
第二步将@Transactional 注解添加到合适的方法上,并设置合适的属性信息。@Transactional 注解的属性信息如表 1 展现。数据库
表 1. @Transactional 注解的属性信息 属性名 说明 name 当在配置文件中有多个 TransactionManager , 能够用该属性指定选择哪一个事务管理器。 propagation 事务的传播行为,默认值为 REQUIRED。详细见:https://blog.csdn.net/soonfly/article/details/70305683 isolation 事务的隔离度,默认值采用 DEFAULT。 timeout 事务的超时时间,默认值为-1。若是超过该时间限制但事务尚未完成,则自动回滚事务。 read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不须要事务的方法,好比读取数据,能够设置 read-only 为 true。 rollback-for 用于指定可以触发事务回滚的异常类型,若是有多个异常类型须要指定,各种型之间能够经过逗号分隔。 no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务。
Spring事务隔离级别(5种)
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
已提交读 (read commited):避免脏读。可是不可重复读和虚读有可能发生
可重复读 (repeatable read) :避免脏读和不可重复读.可是虚读有可能发生.
串行化的 (serializable) :避免以上全部读问题.编程
在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行以前建立并加入事务,并执行目标方法的逻辑, 最后根据执行状况是否出现异常,利用抽象事务管理器(图 2 有相关介绍)AbstractPlatformTransactionManager 操做数据源 DataSource 提交或回滚事务, 如图 1 所示。ui
当您对 Spring 的基于注解方式的实现步骤和事务内在实现机制有较好的理解以后,就会更好的使用注解方式的事务管理,避免当系统抛出异常,数据不能回滚的问题。this
(1)正确的设置@Transactional 的 propagation 属性
须要注意下面三种 propagation 能够不启动事务。原本指望目标方法进行事务管理,但如果错误的配置这三种 propagation,事务将不会发生回滚。编码
TransactionDefinition.PROPAGATION_SUPPORTS:若是当前存在事务,则加入该事务;若是当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,若是当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,若是当前存在事务,则抛出异常。
(2)正确的设置@Transactional 的 rollbackFor 属性
默认状况下,若是在事务中抛出了未检查异常(继承自 RuntimeException 的异常)或者 Error,则 Spring 将回滚事务;除此以外,Spring 不会回滚事务。
若是在事务中抛出其余类型的异常,并指望 Spring 可以回滚事务,能够指定 rollbackFor。例:spa
@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class)
经过分析 Spring 源码能够知道,若在目标方法中抛出的异常是 rollbackFor 指定的异常的子类,事务一样会回滚。.net
清单 3. RollbackRuleAttribute 的 getDepth 方法
private int getDepth(Class<?> exceptionClass, int depth) { if (exceptionClass.getName().contains(this.exceptionName)) { // Found it! return depth; } // If we've gone as far as we can go and haven't found it... if (exceptionClass == Throwable.class) { return -1; } return getDepth(exceptionClass.getSuperclass(), depth + 1); }
(3)@Transactional 只能应用到 public 方法才有效
只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是由于在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行先后进行拦截以前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 经过这个类获取表 1. @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。
清单 4. AbstractFallbackTransactionAttributeSource
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 来拦截该目标方法进行事务管理。
(4)避免 Spring 的 AOP 的自调用问题
在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会形成自调用问题。若同一类中的其余没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。见清单 5 举例代码展现。
清单 5.自调用问题举例
@Service -->public class OrderService { private void insert() { insertOrder(); } @Transactional public void insertOrder() { //insert log info //insertOrder //updateAccount } }
insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。
参考:
https://www.ibm.com/developer...
https://blog.csdn.net/soonfly...