Spring的事物管理

1、事物的定义和特性java

事物表明的是一个操做集合。也就是一连串的操做为一个最小单元不可分割(原子性),这一连串的操做要么所有成功要不所有失败(一致性),每个操做集合互不干扰(隔离性),操做集合的全部操做完成后数据必须以一种持久性方式存储起来(持久性)。spring

 

2、Spring的事务管理express

Spring的事务管理分为编程式事物和声明式事物。编程

一、编程式事物管理框架

   基于底层API的编程式事物管理学习

   根据PlateformTransactionManger、TransactionDefinition和TransactionStatus这三个核心接口完成 编程式事物管理。编码

基于底层API的事物管理代码示例spa

1 public class BankServiceImpl implements BankService {
 2 private BankDao bankDao;
 3 private TransactionDefinition txDefinition;
 4 private PlatformTransactionManager txManager;
 5 ......
 6 public boolean transfer(Long fromId, Long toId, double amount) {
 7     TransactionStatus txStatus = txManager.getTransaction(txDefinition);
 8     boolean result = false;
 9 try {
10     result = bankDao.transfer(fromId, toId, amount);
11     txManager.commit(txStatus);
12     } catch (Exception e) {
13         result = false;
14         txManager.rollback(txStatus);
15         System.out.println("Transfer Error!");
16     }
17     return result;
18 }
19 }

基于底层API的配置文件代码示例代理

<bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="txManager" ref="transactionManager"/>
<property name="txDefinition">
<bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
</property>
</bean>

基于TransactionTemplate的编程式事物管理code

这种是上面的简化版

public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionTemplate transactionTemplate;
......
public boolean transfer(final Long fromId, final Long toId, final double amount) {
return (Boolean) transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status) {
Object result;
    try {
        result = bankDao.transfer(fromId, toId, amount);
    } catch (Exception e) {
        status.setRollbackOnly();
        result = false;
        System.out.println("Transfer Error!");
    }
    return result;
    }
});
}
}

配置文件示例

<bean id="bankService"
class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

TransactionTemplate 的 execute() 方法有一个 TransactionCallback 类型的参数,该接口中定义了一个 doInTransaction() 方法,一般咱们以匿名内部类的方式实现 TransactionCallback 接口,并在其 doInTransaction() 方法中书写业务逻辑代码。这里可使用默认的事务提交和回滚规则,这样在业务代码中就不须要显式调用任何事务管理的 API。doInTransaction() 方法有一个TransactionStatus 类型的参数,咱们能够在方法的任何位置调用该参数的 setRollbackOnly() 方法将事务标识为回滚的,以执行事务回滚。

根据默认规则,若是在执行回调方法的过程当中抛出了未检查异常,或者显式调用了TransacationStatus.setRollbackOnly() 方法,则回滚事务;若是事务执行完成或者抛出了 checked 类型的异常,则提交事务。

TransactionCallback 接口有一个子接口 TransactionCallbackWithoutResult,该接口中定义了一个 doInTransactionWithoutResult() 方法,TransactionCallbackWithoutResult 接口主要用于事务过程当中不须要返回值的状况。固然,对于不须要返回值的状况,咱们仍然可使用 TransactionCallback 接口,并在方法中返回任意值便可。

二、声明式事物管理

Spring 的声明式事务管理在底层是创建在 AOP 的基础之上的。其本质是对方法先后进行拦截,而后在目标方法开始以前建立或者加入一个事务,在执行完目标方法以后根据执行状况提交或者回滚事务。

声明式事务最大的优势就是不须要经过编程的方式管理事务,这样就不须要在业务逻辑代码中掺琐事务管理的代码,只需在配置文件中作相关的事务规则声明(或经过等价的基于标注的方式),即可以将事务规则应用到业务逻辑中。由于事务管理自己就是一个典型的横切逻辑,正是 AOP 的用武之地。Spring 开发团队也意识到了这一点,为声明式事务提供了简单而强大的支持。

声明式事务管理曾经是 EJB 引觉得傲的一个亮点,现在 Spring 让 POJO 在事务管理方面也拥有了和 EJB 同样的待遇,让开发人员在 EJB 容器以外也用上了强大的声明式事务管理功能,这主要得益于 Spring 依赖注入容器和 Spring AOP 的支持。依赖注入容器为声明式事务管理提供了基础设施,使得 Bean 对于 Spring 框架而言是可管理的;而 Spring AOP 则是声明式事务管理的直接实现者,这一点经过清单8能够看出来。

一般状况下,笔者强烈建议在开发中使用声明式事务,不只由于其简单,更主要是由于这样使得纯业务代码不被污染,极大方便后期的代码维护。

和编程式事务相比,声明式事务惟一不足地方是,后者的最细粒度只能做用到方法级别,没法作到像编程式事务那样能够做用到代码块级别。可是即使有这样的需求,也存在不少变通的方法,好比,能够将须要进行事务管理的代码块独立为方法等等。

下面就来看看 Spring 为咱们提供的声明式事务管理功能。

基于 TransactionInter... 的声明式事务管理

Spring 提供了 TransactionInterceptor 类来实施声明式事务管理功能。

<beans...>
......
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
......
</beans>

基于 TransactionProxy... 的声明式事务管理

<beans......>
......
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
......
</beans>

基于 <tx> 命名空间的声明式事务管理

前面两种声明式事务配置方式奠基了 Spring 声明式事务管理的基石。在此基础上,Spring 2.x 引入了 <tx> 命名空间,结合使用 <aop> 命名空间,带给开发人员配置声明式事务的全新体验,配置变得更加简单和灵活。另外,得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得更增强大。

<beans......>
......
<bean id="bankService"
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
 
<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>

若是默认的事务属性就能知足要求,那么代码简化为

<beans......>
......
<bean id="bankService"
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>

因为使用了切点表达式,咱们就不须要针对每个业务类建立一个代理对象了。另外,若是配置的事务管理器 Bean 的名字取值为“transactionManager”,则咱们能够省略 <tx:advice> 的 transaction-manager 属性,由于该属性的默认值即为“transactionManager”。

基于 @Transactional 的声明式事务管理

除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 能够做用于接口、接口方法、类以及类方法上。看成用于类上时,该类的全部 public 方法将都具备该类型的事务属性,同时,咱们也能够在方法级别使用该标注来覆盖类级别的定义。

@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long fromId, Long toId, double amount) {
return bankDao.transfer(fromId, toId, amount);
}

Spring 使用 BeanPostProcessor 来处理 Bean 中的标注,所以咱们须要在配置文件中做以下声明来激活该后处理 Bean

启用处理Bean

<tx:annotation-driven transaction-manager="transactionManager"/>

与前面类似,transaction-manager 属性的默认值是 transactionManager,若是事务管理器 Bean 的名字即为该值,则能够省略该属性。

虽然 @Transactional 注解能够做用于接口、接口方法、类以及类方法上,可是 Spring 小组建议不要在接口或者接口方法上使用该注解,由于这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。若是你在 protected、private 或者默承认见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

基于 <tx> 命名空间和基于 @Transactional 的事务声明方式各有优缺点。基于 <tx> 的方式,其优势是与切点表达式结合,功能强大。利用切点表达式,一个配置能够匹配多个方法,而基于 @Transactional 的方式必须在每个须要使用事务的方法或者类上用 @Transactional 标注,尽管可能大多数事务的规则是一致的,可是对 @Transactional 而言,也没法重用,必须逐个指定。另外一方面,基于 @Transactional 的方式使用起来很是简单明了,没有学习成本。开发人员能够根据须要,任选其中一种使用,甚至也能够根据须要混合使用这两种方式。

若是不是对遗留代码进行维护,则不建议再使用基于 TransactionInterceptor 以及基于TransactionProxyFactoryBean 的声明式事务管理方式,可是,学习这两种方式很是有利于对底层实现的理解。

 

  • 基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务管理是 Spring 提供的最原始的方式,一般咱们不会这么写,可是了解这种方式对理解 Spring 事务管理的本质有很大做用。
  • 基于 TransactionTemplate 的编程式事务管理是对上一种方式的封装,使得编码更简单、清晰。
  • 基于 TransactionInterceptor 的声明式事务是 Spring 声明式事务的基础,一般也不建议使用这种方式,可是与前面同样,了解这种方式对理解 Spring 声明式事务有很大做用。
  • 基于 TransactionProxyFactoryBean 的声明式事务是上中方式的改进版本,简化的配置文件的书写,这是 Spring 早期推荐的声明式事务管理方式,可是在 Spring 2.0 中已经不推荐了。
  • 基于 <tx> 和 <aop> 命名空间的声明式事务管理是目前推荐的方式,其最大特色是与 Spring AOP 结合紧密,能够充分利用切点表达式的强大支持,使得管理事务更加灵活。
  • 基于 @Transactional 的方式将声明式事务管理简化到了极致。开发人员只需在配置文件中加上一行启用相关后处理 Bean 的配置,而后在须要实施事务管理的方法或者类上使用 @Transactional 指定事务规则便可实现事务管理,并且功能也没必要其余方式逊色。
相关文章
相关标签/搜索