Spring 事務管理原理探究


此處先粘貼出Spring事務需要的配置內容:
1、Spring事務管理器的配置文件:
<bean id="transactionManager"  
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
   <property name="dataSource" ref="dataSource" />.....  
</bean>
2、一個普通的JPA框架(此處是mybatis)的配置文件:    
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
   <property name="dataSource" ref="dataSource" />  
   .....         
</bean>
  這兩個里面都配置了datasource,而且這個datasource的對象是在Spring的容器里面。一下提幾個問題:
            1、當JPA框架對數據庫進行操作的時候,是從那里獲取Connection?
            2、jdbc對事務的配置,比如事務的開啟,提交以及回滾是在哪里設置的?
            3、Spring是通過aop攔截切面的所有需要進行事務管理的業務處理方法,那如何獲取業務處理方法里面對數據庫操作的事務呢?
           現在我來對上面的問題來一一回答
           1、這個問題很簡單,既然在JPA的框架里面配置了datasource,那自然會從這個datasource里面去獲得連接。
           2、jdbc的事務配置是在Connection對消里面有對應的方法,比如setAutoCommit,commit,rollback這些方法就是對事務的操作。
           3、Spring需要操作事務,那必須要對Connection來進行設置。Spring的AOP可以攔截業務處理方法,並且也知道業務處理方法里面的DAO操作的JAP框架是從datasource里面獲取Connection對象,那么Spring需要對當前攔截的業務處理方法進行事務控制,那必然需要得到他內部的Connection對象。整體的結構圖如下:
           

Spring 事務管理創造性的解決了很多以前要用重量級的應用服務器才能解決的事務問題,那么其實現原理一定很深奧吧?可是如果讀者仔細研究了Spring事務管理的代碼以后就會發現,事務管理其實也是如此簡單的事情。這也印證了在本書開頭的一句話“重劍無鋒、大巧不工”,Spring並沒有使用什么特殊的API,它運行的原理就是事務的原理。下面是DataSourceTransactionManager的啟動事務用的代碼(經簡化):

protected void doBegin(Object transaction, TransactionDefinition definition)
{
 DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
 Connection con = null;
 try
 {
  if (txObject.getConnectionHolder() == null)
  {
     Connection newCon = this.dataSource.getConnection();
     txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
  }
  txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
  con = txObject.getConnectionHolder().getConnection();

  Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
  txObject.setPreviousIsolationLevel(previousIsolationLevel);
  if (con.getAutoCommit())
  {
    txObject.setMustRestoreAutoCommit(true);
    con.setAutoCommit(false);
  }
  txObject.getConnectionHolder().setTransactionActive(true);
  // Bind the session holder to the thread.
  if (txObject.isNewConnectionHolder())
  {
   TransactionSynchronizationManager.bindResource(getDataSource(),txObject.getConnectionHolder());
  }
 }
 catch (SQLException ex)
 {
  DataSourceUtils.releaseConnection(con, this.dataSource);
  throw new CannotCreateTransactionException( "Could not open JDBC Connection for transaction", ex);
 }
}

在調用一個需要事務的組件的時候,管理器首先判斷當前調用(即當前線程)有沒有一個事務,如果沒有事務則啟動一個事務,並把事務與當前線程綁定。Spring使TransactionSynchronizationManager的bindResource方法將當前線程與一個事務綁定,采用的方式就是ThreadLocal,這可以從TransactionSynchronizationManager類的代碼看出。

public abstract class TransactionSynchronizationManager 
{
 ……
 private static final ThreadLocal currentTransactionName = new ThreadLocal();
 private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
 private static final ThreadLocal actualTransactionActive = new ThreadLocal(); ……
}

從doBegin的代碼中可以看到在啟動事務的時候,如果Connection是的自動提交的(也就是getAutoCommit()方法返回true)則事務管理就會失效,所以首先要調用setAutoCommit(false)方法將其改為非自動提交的。setAutoCommit(false)這個動作在有的JDBC驅動中會非常耗時,所以最好在配置數據源的時候就將“autoCommit”屬性配置為true。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM