首页 > 代码库 > Spring源码阅读:Spring声明式事务处理和编程式事务处理的设计与实现

Spring源码阅读:Spring声明式事务处理和编程式事务处理的设计与实现

 

    之前的学习,了解了Spring事务管理的基础框架(查看)。Spring在此基础上又提到了声明式事务管理和编程式事务管理。这里就来看看Spring是如何实现的。

 

Spring声明式事务与EJB事务管理对比

 

    Spring的声明式管理,类似于EJB的CMT,但又有不同。他们的不同之处有:

1)EJB的CMT是与JTA结合使用,而Spring框架的声明式事务管理可以在任何环境下工作。既可以使用全局事务管理,如JTA,也可以使用局部事务管理如JDBCJPA、Hibernate、JDO等。

2)可以在任何类中使用Spring的声明式事务管理。但EJB就不行,它只能在特定的类中使用。

3)Spring中提供了一些与EJB中不同的回滚原则(都有回滚原则,但Spring中有些是与EJB中不同的)。这些回滚原则在编程式事务管理和声明式事务管理中都是可用的。

4)Spring框架可以让你使用AOP方式自定义一些事务行为。而在EJB中,是不可以的。

5)Spring框架不支持远程调用的事务传播机制上下文。如果应用中需要支持在远程调用时的事务传播机制,需要使用EJB了。

 

 

Spring声明式事务管理

 

 

    Spring声明式事务管理,是采用AOP原理实现(查看)的。之前看Spring AOP的源码时知道,Spring AOP是通过创建代理(CGI代理或者JDK代理(查看)),代理调用AOP拦截器链,然后调用真实的处理,返回结果。

    接下来看看Spring声明式事务管理是如何实现的:

 

 

 

 

 

 

 

 

根据上图,可以猜测:Caller执行方法调用时,先Spring容器为其创建AOP代理,根据代理获取到它的拦截器,调用拦截器链处理,然后进行方法调用,最后拦截器链做后置处理,并返回结果。

事务管理是作为一个Advistor出现的,Advistor,就是Advice的持有者,通过它就能找到Advice,也就是够找到Interceptor,所以就简单的理解为Spring是把事务处理作为一个拦截器放置在其他的拦截器前面。

 

上面是根据调用流程图猜测的,接下来看看Spring中是如何处理的:

 

 

TransactionAttributeSourceAdvistor就是上面原理图中的Advistor,也是SpringAOP要用的Advistor。在他的内部,的确是有一个拦截器TransactionInterceptor。接下来看看这个拦截器(只看主要部分):

 

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {public Object invoke(final MethodInvocation invocation) throws Throwable {      // Work out the target class: may be <code>null</code>.      // The TransactionAttributeSource should be passed the target class      // as well as the method, which may be from an interface.      Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);       // If the transaction attribute is null, the method is non-transactional.      final TransactionAttribute txAttr =            getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);// 取到PlatformTransactionManager事务管理对象      final PlatformTransactionManager tm = determineTransactionManager(txAttr);      final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass);       if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {         // Standard transaction demarcation with getTransaction and commit/rollback calls.         TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);         Object retVal = null;         try {            // This is an around advice: Invoke the next interceptor in the chain.            // This will normally result in a target object being invoked.// 调用拦截器链其他的拦截器(AOP建议)处理,最后调用target方法            retVal = invocation.proceed();         }         catch (Throwable ex) {            // target invocation exception// 必要时抛出异常            completeTransactionAfterThrowing(txInfo, ex);            throw ex;         }         finally {            cleanupTransactionInfo(txInfo);         }// 事务提交         commitTransactionAfterReturning(txInfo);         return retVal;      }       else {// 针对WebsphereUowTransactionManager的处理。         // It‘s a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.         try {            Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,                   new TransactionCallback<Object>() {                      public Object doInTransaction(TransactionStatus status) {                         TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);                         try {                            return invocation.proceed();                         }                         catch (Throwable ex) {                            if (txAttr.rollbackOn(ex)) {                               // A RuntimeException: will lead to a rollback.                               if (ex instanceof RuntimeException) {                                  throw (RuntimeException) ex;                               }                               else {                                  throw new ThrowableHolderException(ex);                               }                            }                            else {                               // A normal return value: will lead to a commit.                               return new ThrowableHolder(ex);                            }                         }                         finally {                            cleanupTransactionInfo(txInfo);                         }                      }                   });             // Check result: It might indicate a Throwable to rethrow.            if (result instanceof ThrowableHolder) {                throw ((ThrowableHolder) result).getThrowable();            }            else {                return result;            }         }         catch (ThrowableHolderException ex) {            throw ex.getCause();         }      }   }}
View Code

  

显而易见,这里的代码验证了我对于上面的Spring事务处理模型图猜测的正确性。这样得益于之前的对于AOP的理解(查看,查看)。另外如果没有之前的源码学习,而直接看这部分,是很难理解的。

 

从这部分源码中,看到了Spring默认的就帮助我们处理了异常。所以我们在写代码时,可以不做异常处理的。

 

 

声明式事务处理的两种配置方式

 

因为声明式事务处理底层是使用AOP实现的。所以在项目 中可以有两种配置声明式事务处理的方式:使用XML或者使用@Transactional

 

使用XML方式配置:

 

 

 

注解方式配置:

 

 

 

在代码中 加入注解就行了:

 

对于readonly,proagation等属性的理解配置,上一篇博客(查看)中已经学习了。

 

Spring编程式事务管理

    顾名思义,就是我们处理业务逻辑时自己写有关事务处理的代码。

在做Spring编程式事务处理时,Spring依旧使用了模板方法模式,这个模式Spring是屡试不爽呀。

    上一篇文章中也说了Spring推荐使用TransactionTemplate来完成处理编程式事务处理。看看模板方法中是怎么写的:

public <T> T execute(TransactionCallback<T> action) throws TransactionException {      if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {        return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);      }      else {        TransactionStatus status = this.transactionManager.getTransaction(this);        T result;        try {           result = action.doInTransaction(status);        }        catch (RuntimeException ex) {           // Transactional code threw application exception -> rollback           rollbackOnException(status, ex);           throw ex;        }        catch (Error err) {           // Transactional code threw error -> rollback           rollbackOnException(status, err);           throw err;        }        catch (Exception ex) {           // Transactional code threw unexpected exception -> rollback           rollbackOnException(status, ex);           throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");        }        this.transactionManager.commit(status);        return result;      }   }
View Code

 


采用了带有回调函数的模板方法来处理(不理解可以参考模板方法模式)。我们在回调函数中写上要进行事务处理实际的业务逻辑代码就行了。这个模板替我们做了两件事:1)事务的管理,2)异常的处理。
 

 

我们使用时,只需如此:

 

在使用编程式事务处理式,也可以直接的使用PlatformTransactionManager的实现类来完成上述操作:

例如

 

 

这个就不详细说明了,这个与上节中的知识也是紧密相关的。由于写起来比较麻烦,并不推荐使用。

 

 

如何选择?

 

如果你的项目比较小,只有少量的Update操作时,可以采用编程式事务处理,即使用TransactionTemplate即可。除此之外,还是推荐使用声明式事务处理,方便,只需要集中处理业务逻辑即可。

 

当然要用好声明式事务处理,上一篇博客中的内容可以是很重要的哟。