Spring Boot事务管理和@Transactional注解(上)

摘要 本文主要介绍基于Spring Boot的事务管理,尤其是@Transactional注解详细用法。首先,简要介绍Spring Boot中如何开启事务管理;其次,介绍在Spring,Spring Boot和Mybatis框架中的事务管理方式;然后,介绍了事务的五个属性,包括事务传播行为和事务隔离级别等;最后,介绍了注解@Transactional属性。 

1 事务概念

       理解事务之前,先讲一个你日常生活中最常干的事:取钱。  
       比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。  
       事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。  通俗理解,事务其实就是一系列指令的集合。 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
 
      在企业级应用程序开发中,事务管理是必不可少的技术,用来确保数据的完整性和一致性。 事务有四个特性:ACID 
  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不执行。
  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其它事务隔离开来,防止数据损坏。
  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

 

2 Spring Boot开启事务管理

       本节直接研究Spring Boot中事务的开启方法。

       Spring Boot内部提供的事务管理器是根据@AutoConfigure来进行决定的,当我们使用spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框架会自动分别注入DataSourceTransactionManager或JpaTransactionManager。这两个事务管理器都实现了Spring中提供的PlatformTransactionManager接口,它是Spring的事务核心接口。

      Spring Boot 默认集成事务,所以无须手动开启。使用注解 @EnableTransactionManagement后,Spring 会自动扫描添加@Transactional注解的方法和类。在Spring Boot中推荐使用@Transactional注解来申明事务。 

     在Spring MVC框架中,为了使用基于@Transactional的事务管理,需要进行如下的配置: 
<beans:bean id="transactionManager"  
    class="org.springframework.orm.jpa.JpaTransactionManager">  
    <beans:property name="dataSource" ref="dataSource" />  
    <beans:property name="entityManagerFactory" ref="entityManagerFactory" />  
</beans:bean>
<!-- 声明使用注解式事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />

     dataSource是在Spring配置文件中定义的数据源的对象实例,EntityManagerFactory是基于JPA使用的实体类管理器:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean。这些都是用来配置与数据库的连接信息,本质上,@Transactional使用了JDBC的事务来进行事务控制的。

     <annotation-driven>标签的声明,则是在Spring内部启用@Transactional来进行事务管理,类似开关之类的声明。

 

3 核心接口

      Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略。Spring事务管理涉及的接口的联系如下:

 

 

      Spring并不直接管理事务,而是提供了多种事务管理器,管理器将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现,它的接口是org.Springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:

public interface PlatformTransactionManager {

TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

void commit(TransactionStatus status) throws TransactionException;

void rollback(TransactionStatus status) throws TransactionException;

}

     TransactionStatus接口表示事务的状态,比如事务是否是一个刚构造的事务,事务是否已经执行完成等状态。

4 事务管理方式

       Spring支持编程式事务管理和声明式事务管理两种方式。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager,Spring推荐使用TransactionTemplate。

       声明式事务管理在底层是建立在AOP之上的。其本质是在方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

       显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一的不足之处是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

       声明式事务管理也有两种常用的方式,一种是使用<tx:advice>进行声明式事务管理,另一种就是基于Java注解@Transactional。显然后者更简单易用,更清爽。

        MyBatis自动参与到Spring事务管理中,无需额外配置,只要org.mybatis.Spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager或JpaTransactionManager引用的数据源一致即可;否则,事务管理会不起作用。

        预知后事如何,请听下回分解——Spring Boot事务管理(中)

 

posted @ 2019-03-23 21:30  楼兰胡杨  阅读(3009)  评论(0编辑  收藏  举报