知识大全 Spring声明式事务管理源码解读之事务提交

Posted

篇首语:弱龄寄事外,委怀在琴书。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Spring声明式事务管理源码解读之事务提交相关的知识,希望对你有一定的参考价值。

Spring声明式事务管理源码解读之事务提交  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  其实我的感觉就是事务提交要比事务开始复杂 看事务是否提交我们还是要回到TransactionInterceptor类的invoke方法

  Java代码

  

  public Object invoke(MethodInvocation invocation) throws Throwable // Work out the target class: may be null // The TransactionAttributeSource should be passed the target class // as well as the method which may be from an interface Class targetClass = (invocation getThis() != null) ? invocation getThis() getClass() : null; // Create transaction if necessary TransactionInfo txInfo = createTransactionIfNecessary(invocation getMethod() targetClass); 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 retVal = invocation proceed(); catch (Throwable ex) // target invocation exception doCloseTransactionAfterThrowing(txInfo ex); throw ex; finally doFinally(txInfo);//业务方法出栈后必须先执行的一个方法 doCommitTransactionAfterReturning(txInfo); return retVal;

  其中的doFinally(txInfo)那一行很重要 也就是说不管如何 这个doFinally方法都是要被调用的 为什么它这么重要呢 举个例子

  我们还是以propregation_required来举例子吧 假设情况是这样的 AService中有一个方法调用了BService中的 这两个方法都处在事务体之中 他们的传播途径都是required 那么调用开始了 AService的方法首先入方法栈 并创建了TransactionInfo的实例 接着BService的方法入栈 又创建了一个TransactionInfo的实例 而重点要说明的是TransactionInfo是一个自身关联的内部类 第二个方法入栈时 会给新创建的TransactionInfo的实例设置一个属性 就是TransactionInfo对象中的private TransactionInfo oldTransactionInfo;属性 这个属性表明BService方法的创建的TransactionInfo对象是有一个old的transactionInfo对象的 这个oldTransactionInfo对象就是AService方法入栈时创建的TransactionInfo对象 我们还记得在createTransactionIfNecessary方法里有这样一个方法吧

  Java代码

   protected TransactionInfo createTransactionIfNecessary(Method method Class targetClass) // We always bind the TransactionInfo to the thread even if we didn t create// a new transaction here This guarantees that the TransactionInfo stack// will be managed correctly even if no transaction was created by this aspect txInfo bindToThread();return txInfo;就是这个bindToThread()方法在作怪 private void bindToThread() // Expose current TransactionStatus preserving any existing transactionStatus for// restoration after this transaction is plete oldTransactionInfo = (TransactionInfo) currentTransactionInfo get();currentTransactionInfo set(this);

  如果当前线程中已经有了一个TransactionInfo 则拿出来放到新建的transactionInfo对象的oldTransactionInfo属性中 然后再把新建的TransactionInfo设置到当前线程中

  这里有一个概念要搞清楚 就是TransactionInfo对象并不是表明事务状态的对象 表明事务状态的对象是TransactionStatus对象 这个对象同样是TransactionInfo的一个属性

  接下来BService中的那个方法返回 那么该它退栈了 它退栈后要做的就是doFinally方法 即把它的oldTransactionInfo设置到当前线程中(这个TransactionInfo对象显然就是AService方法入栈时创建的 怎么现在又要设置到线程中去呢 原因就是BService的方法出栈时并不提交事务 因为BService的传播途径是required 所以要把栈顶的方法所创建transactioninfo给设置到当前线程中) 即调用AService的方法时所创建的TransactionInfo对象 那么在AServie的方法出栈时同样会设置TransactionInfo对象的oldTransactionInfo到当前线程 这时候显然oldTransactionInfo是空的 但AService中的方法会提交事务 所以它的oldTransactionInfo也应该是空了

  在这个小插曲之后 接下来就应该是到提交事务了 之前在AService的方法出栈时 我们拿到了它入栈时创建的TransactionInfo对象 这个对象中包含了AService的方法事务状态 即TransactionStatus对象 很显然 太显然了 事务提交中的任何属性都和事务开始时的创建的对象息息相关 这个TransactionStatus对象哪里来的 我们再回头看看createTransactionIfNessary方法吧

  Java代码

  

  protected TransactionInfo createTransactionIfNecessary(Method method Class targetClass) txInfo newTransactionStatus(this transactionManager getTransaction(txAttr));

  再看看transactionManager getTransaction(txAttr)方法吧

  Java代码

  

  public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException else if (definition getPropagationBehavior() == TransactionDefinition PROPAGATION_REQUIRED ||definition getPropagationBehavior() == TransactionDefinition PROPAGATION_REQUIRES_NEW ||definition getPropagationBehavior() == TransactionDefinition PROPAGATION_NESTED) if (debugEnabled) logger debug( Creating new transaction with name [ + definition getName() + ] );doBegin(transaction definition);boolean newSynchronization = (this transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition transaction true newSynchronization debugEnabled null);//注意这里的返回值 返回的就是一个TransactionStatus对象 这个对象表明了一个事务的状态 比如说是否是一个新的事务 事务是否已经结束 等等 这个对象是非常重要的 在事务提交的时候还是会用到它的

  还有一点需要说明的是 AService的方法在执行之前创建的transactionstatus确实是通过这个方法创建的 但是 BService的方法在执行之前创建transactionstatus的方法就与这个不一样了 下面会有详解

  回顾了事务开始时所调用的方法之后 是不是觉得现在对spring如何处理事务越来越清晰了呢 由于这么几个方法的调用 每个方法入栈之前它的事务状态就已经被设置好了 这个事务状态就是为了在方法出栈时被调用而准备的

  让我们再次回到BService中的方法出栈的那个时间段 看看spring都做了些什么 我们知道 后入栈的肯定是先出栈 BService中的方法后入栈 那它肯定要先出栈了 它出栈的时候是要判断是否要提交事务 释放资源的 让我们来看看TransactionInterceptor的invoke的最后那个方法doCommitTransactionAfterReturning

  Java代码

  

  protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) if (txInfo != null && txInfo hasTransaction()) if (logger isDebugEnabled()) logger debug( Invoking mit for transaction on + txInfo joinpointIdentification());this trmit(txInfo getTransactionStatus());//瞧 提交事务时用到了表明事务状态的那个TransactionStatus对象了

  看这个方法的名字就知道spring是要在业务方法出栈时提交事务 貌似很简单 但是事实是这样的吗?我们接着往下看

  Java代码

public final void mit(TransactionStatus status) throws TransactionException DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;if (defStatus isCompleted()) throw new IllegalTransactionStateException( Transaction is already pleted do not call mit or rollback more than once per transaction );if (defStatus isLocalRollbackOnly()) if (defStatus isDebug()) logger debug( Transactional code has requested rollback );processRollback(defStatus);return;if (!shouldCommitOnGlobalRollbackOnly() && defStatus isGlobalRollbackOnly()) if (defStatus isDebug()) logger debug( Global transaction is marked as rollback only but transactional code requested mit );processRollback(defStatus);throw new UnexpectedRollbackException( Transaction has been rolled back because it has been marked as rollback only );processCommit(defStatus);

  上面这段代码就是transactionmanager中的mit 但是看上去 它又把自己的职责分配给别人了 从代码里我们看到 如果事务已经结束了就抛异常 如果事务是rollbackonly的 那么就rollback吧 但是按照正常流程 我们还是想来看一下 事务的提交 就是processCommit(status)这个方法吧

  Java代码

private void processCommit(DefaultTransactionStatus status) throws TransactionException try boolean beforeCompletionInvoked = false;try triggerBeforeCommit(status);triggerBeforeCompletion(status);beforeCompletionInvoked = true;if (status hasSavepoint()) if (status isDebug()) logger debug( Releasing transaction savepoint );status releaseHeldSavepoint();else if (status isNewTransaction()) //这个判断非常重要 下面会详细讲解这个判断的作用if (status isDebug()) logger debug( Initiating transaction mit );boolean globalRollbackOnly = status isGlobalRollbackOnly();doCommit(status);// Throw UnexpectedRollbackException if we have a global rollback only// marker but still didn t get a corresponding exception from mit `````````````````````

  我们注意到 在判断一个事务是否是新事务之前还有一个status hasSavepoint()的判断 我认为这个判断事实上就是嵌套事务的判断 即判断这个事务是否是嵌套事务 如果不是嵌套事务 则再判断它是否是一个新事务 下面这段话就非常重要了 BService的中的方法是先出栈的 也就是说在调用BService之前的创建的那个事务状态对象在这里要先被判断 但是由于在调用BService的方法之前已经创建了一个Transaction和Session(假设我们使用的是hibernate ) 这时候在创建第二个TransactionInfo(再强调一下吧 TransactionInfo并不是Transaction Transaction是真正的事务对象 TransactionInfo只不过是一个辅助类而已 用来记录一系列状态的辅助类)的TransactionStatus的时候就会进入下面这个方法(当然在这之前会判断一下当前线程中是否已经有了一个SessionHolder对象 不清楚SessionHolder作用的同学请看第一篇文章)

  Java代码

private TransactionStatus handleExistingTransaction(TransactionDefinition definition Object transaction boolean debugEnabled)throws TransactionException if (definition getPropagationBehavior() == TransactionDefinition PROPAGATION_NEVER) throw new IllegalTransactionStateException( Transaction propagation never but existing transaction found );if (definition getPropagationBehavior() == TransactionDefinition PROPAGATION_NOT_SUPPORTED) if (debugEnabled) logger debug( Suspending current transaction );Object suspendedResources = suspend(transaction);boolean newSynchronization = (this transactionSynchronization == SYNCHRONIZATION_ALWAYS);return newTransactionStatus(definition null false newSynchronization debugEnabled suspendedResources);if (definition getPropagationBehavior() == TransactionDefinition PROPAGATION_REQUIRES_NEW) if (debugEnabled) logger debug( Suspending current transaction creating new transaction with name [ +definition getName() + ] );Object suspendedResources = suspend(transaction);doBegin(transaction definition);boolean newSynchronization = (this transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition transaction true newSynchronization debugEnabled suspendedResources);if (definition getPropagationBehavior() == TransactionDefinition PROPAGATION_NESTED) if (!isNestedTransactionAllowed()) throw new NestedTransactionNotSupportedException( Transaction manager does not allow nested transactions by default + specify nestedTransactionAllowed property with value true );if (debugEnabled) logger debug( Creating nested transaction with name [ + definition getName() + ] );if (useSavepointForNestedTransaction()) // Create savepoint within existing Spring managed transaction // through the SavepointManager API implemented by TransactionStatus // Usually uses JDBC savepoints Never activates Spring synchronization DefaultTransactionStatus status =newTransactionStatus(definition transaction false false debugEnabled null);status createAndHoldSavepoint();return status;else // Nested transaction through nested begin and mit/rollback calls // Usually only for JTA: Spring synchronization might get activated here// in case of a pre existing JTA transaction doBegin(transaction definition);boolean newSynchronization = (this transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition transaction true newSynchronization debugEnabled null);// Assumably PROPAGATION_SUPPORTS if (debugEnabled) logger debug( Participating in existing transaction );boolean newSynchronization = (this transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition transaction false newSynchronization debugEnabled null);

  我们看到这个方法其实很明了 就是什么样的传播途径就创建什么样的transactionstatus 这个方法是在事务开始时被调用的 拿到我们之前举的例子中来看下 我们就恍然大悟了 原来 如果之前已经创建过事务 那个这个新建的transactionstauts就不应该是属于一个newTransaction了 所以第 个参数就是false了

  也就是说 在BService的方法出栈要要执行processmit 但是由于BService的那个TransactionStatus不是一个newTransaction 所以它根本不会触发这个动作

  Java代码

  

  else if (status isNewTransaction()) //这个判断非常重要 下面会详细讲解这个判断的作用if (status isDebug()) logger debug( Initiating transaction mit );boolean globalRollbackOnly = status isGlobalRollbackOnly();doCommit(status);

  也就是说在BService的方法出栈后 事务是不会提交的 这完全符合propragation_required的模型

  而在AService的方法出栈后 AService的方法所对应的那个TransactionStatus对象的newTransaction属性是为true的 即它会触发上面这段代码 进行真正的事务提交 让我们回想一下AService方法入栈之前创建TransactionStatus对象的情形吧

  

  newTransactionStatus(definition transaction true newSynchronization debugEnabled null);

  看到第 个参数为true没有

  那么事务该提交了吧 事务的提交我想使用过hibernate的人都知道怎么提交了

  

  txObject getSessionHolder() getTransaction(mit();

cha138/Article/program/Java/ky/201311/28431

相关参考

知识大全 Spring中的四种声明式事务的配置

Spring中的四种声明式事务的配置  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Spring

政务类事务文书包括了计划、启事、声明、调査报告等

政务类事务文书包括了计划、启事、声明、调査报告等。_____答案:错误解析:政务类事务文书指的是行政公文,包括命令(令)、决定、公告、通告、通知、通报、议案、报告、请示、批复、意见、函、会议纪要。(注

知识大全 Spring 事务管理

Spring事务管理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  数据库事务是由一系列的动作组

知识大全 Spring的事务

Spring的事务  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  今天对spring的AOP事务

知识大全 浅析Spring提供的事务管理方法

浅析Spring提供的事务管理方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Spring提

知识大全 spring事务配置

  <!构建HibernateTransactionManager用于获得session管理事务>  <beanid=transactionManagerclass=springfr

知识大全 Spring事务管理高级应用难点剖析(4)

Spring事务管理高级应用难点剖析(4)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  多线程

知识大全 Spring事务管理高级应用难点剖析(2)

Spring事务管理高级应用难点剖析(2)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  应用分

知识大全 SPring管理Hibernate事务出现异常处理

SPring管理Hibernate事务出现异常处理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 Spring+Ibatis+事务处理

Spring+Ibatis+事务处理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  applic