Spring事务:一种编程式事务,三种声明式事务

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:spring

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,一般这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务能够读取另外一个事务修改但尚未提交的数据。该级别不能防止脏读和不可重复读,所以不多使用该隔离级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另外一个事务已经提交的数据。该级别能够防止脏读,这也是大多数状况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程当中能够屡次重复执行某个查询,而且每次返回的记录都相同。即便在屡次查询之间有新增的数据知足该查询,这些新增的记录也会被忽略。该级别能够防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:全部的事务依次逐个执行,这样事务之间就彻底不可能产生干扰,也就是说,该级别能够防止脏读、不可重复读以及幻读。可是这将严重影响程序的性能。一般状况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,若是在开始当前事务以前,一个事务上下文已经存在,此时有若干选项能够指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了以下几个表示传播行为的常量:数据库

  • TransactionDefinition.PROPAGATION_REQUIRED:若是当前存在事务,则加入该事务;若是当前没有事务,则建立一个新的事务。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:建立一个新的事务,若是当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:若是当前存在事务,则加入该事务;若是当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,若是当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,若是当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:若是当前存在事务,则加入该事务;若是当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:若是当前存在事务,则建立一个事务做为当前事务的嵌套事务来运行;若是当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

这里须要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(若是存在外部事务的话),此时,内嵌事务并非一个独立的事务,它依赖于外部事务的存在,只有经过外部的事务提交,才能引发内部事务的提交,嵌套的子事务不能单独提交。若是熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中能够包括多个保存点,每个嵌套子事务。另外,外部事务的回滚也会致使嵌套子事务的回滚。express

事务超时

所谓事务超时,就是指一个事务所容许执行的最长时间,若是超过该时间限制但事务尚未完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。编程

事务的只读属性

事务的只读属性是指,对事务性资源进行只读操做或者是读写操做。所谓事务性资源就是指那些被事务管理的资源,好比数据源、 JMS 资源,以及自定义的事务性资源等等。若是肯定只对事务性资源进行只读操做,那么咱们能够将事务标志为只读的,以提升事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。并发

事务的回滚规则

一般状况下,若是在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。若是没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这一般也是大多数开发者但愿的处理方式,也是 EJB 中的默认处理方式。可是,咱们能够根据须要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。性能

声明式事务:可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不一样,声明式事务属于无侵入式,不会影响业务逻辑的实现。

声明式事务实现方式主要有3种,一种为基于AOP方式的声明式事务【基于TransactionProxyFactoryBean】,一种为基于AspectJ的声明式事务【一种为经过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现】,另为一种经过@Transactional注解实现事务管理实现,下面详细说明2种方法如何配置,已经相关注意点spa

1)方式一,配置文件以下
<!-- 
<tx:advice>定义事务通知,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并经过<tx:attributes>指定具体须要拦截的方法
    <tx:method>拦截方法,其中参数有:
    name:方法名称,将匹配的方法注入事务管理,可用通配符
    propagation:事务传播行为,
    isolation:事务隔离级别定义;默认为“DEFAULT”
    timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
    read-only:事务只读设置,默认为false,表示不是只读;
    rollback-for:须要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将致使事务回滚,而任何Checked Exception将不致使事务回滚;
    no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割;
 -->
<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 拦截save开头的方法,事务传播行为为:REQUIRED:必需要有事务, 若是没有就在上下文建立一个 -->
        <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
        <!-- 支持,若是有就有,没有就没有 -->
        <tx:method name="*" propagation="SUPPORTS"/>
    </tx:attributes>
</tx:advice>
<!-- 定义切入点,expression为切人点表达式,以下是指定impl包下的全部方法,具体以自身实际要求自定义  -->
<aop:config>
    <aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
    <!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 -->
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
注意点:
  1. 事务回滚异常只能为RuntimeException异常,而Checked Exception异常不回滚,捕获异常不抛出也不会回滚,但能够强制事务回滚:TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
  2. 解决“自我调用”而致使的不能设置正确的事务属性问题,可参考http://www.iteye.com/topic/1122740

2)方式二经过@Transactional实现事务管理代理

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
     <property name="dataSource" ref="dataSource"/>
</bean>    
<tx:annotation-driven transaction-manager="txManager"/> //开启事务注解
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED),具体参数跟上面<tx:method>中同样
Spring提供的@Transaction注解事务管理,内部一样是利用环绕通知TransactionInterceptor实现事务的开启及关闭。

使用@Transactional注意点:
    1. 若是在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
    2. 建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是由于若是使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,由于其使用基于类的代理而不是接口,这是由于接口上的@Transactional注解是“不能继承的”;

3.注意事项code

* 若是配置了声明式事务,在出现运行时异常时,事务会回滚,可是出现非运行时异常时,事务不回滚。blog

* 若是配置了编程式事务,则无论出现什么异常,事务都会回滚。

相关文章
相关标签/搜索