螺 丝 钉 阅读(161) 评论(0)

 

    之前的学习,了解了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即可。除此之外,还是推荐使用声明式事务处理,方便,只需要集中处理业务逻辑即可。

 

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