1. 程式人生 > >Spring 事務的梳理一——事務的屬性

Spring 事務的梳理一——事務的屬性

Spring宣告式事務讓我們從複雜的事務處理中得到解脫。使得我們再也無需要去處理獲得連線、關閉連線、事務提交和回滾等這些操作。再也無需要我們在與事務相關的方法中處理大量的try…catch…finally程式碼。

Spring事務機制主要包括宣告式事務和程式設計式事務,在這篇部落格中,我們主要說宣告式事務的使用。

  而我們在使用Spring宣告式事務時,有一個非常重要的概念就是事務屬性。事務屬性通常由事務的傳播行為,事務的隔離級別,事務的超時值和事務只讀標誌組成。我們在進行事務劃分時,需要進行事務定義,也就是配置事務的屬性。分清楚事務的屬性,我們才能合理的使用事務。使用spring宣告式事務,spring使用AOP來支援宣告式事務,會根據事務屬性,自動在方法呼叫之前決定是否開啟一個事務,並在方法執行之後決定事務提交或回滾事務。

   事務屬性的定義在TransactionDefinition中定義這些屬性,供PlatformTransactionManager使用,這個PlatformTransactionManager是spring事務管理的核心介面。那麼我們來看看transaction中事務屬性的定義:
<span style="font-family:Times New Roman;">public interface TransactionDefinition { 
<span style="white-space:pre">	</span>int getPropagationBehavior();//返回事務的傳播行為。 
<span style="white-space:pre">	</span>int getIsolationLevel();//返回事務的隔離級別,事務管理器根據它來控制另外一個事務可以看到本事務內的哪些資料。 
<span style="white-space:pre">	</span>int getTimeout();//返回事務必須在多少秒內完成。 
<span style="white-space:pre">	</span>boolean isReadOnly();//事務是否只讀,事務管理器能夠根據這個返回值進行優化,確保事務是隻讀的。 
}</span>

事務的傳播行為    首先是事務的傳播行為,我們先巨集觀來看一下如下spring的事務傳播行為: PROPAGATION_REQUIRED--支援當前事務,如果當前沒有事務,就新建一個事務。

PROPAGATION_SUPPORTS--支援當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY--支援當前事務,如果當前沒有事務,就丟擲異常。

PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則丟擲異常。

PROPAGATION_NESTED--如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。
   接下來,我們一一來解釋一下這些傳播行為各自如何來工作的?  PROPAGATION_REQUIRED 支援當前事務,如果當前沒有事務,就新建一個事務,這是最常見的選擇。程式碼如下:     情形一:單獨使用methodB,methodB加了事務傳播行為:
<span style="white-space:pre">	</span>main{ 
<span style="white-space:pre">		</span>metodB(); 
<span style="white-space:pre">	</span>}
等價於:
<span style="font-family:KaiTi_GB2312;font-size:18px;">Main{ 
     Connection con=null; 
  try{ 
    con = getConnection(); 
    con.setAutoCommit(false); 

    //方法呼叫
    methodB(); 
     //提交事務
     con.commit(); 
   } 
   Catch(RuntimeException ex){ 
            //回滾事務
            con.rollback();   
   } 
   finally{ 
         //釋放資源
         closeCon(); 
     } 
} </span>
       Spring保證在methodB方法中所有的呼叫都獲得到一個相同的連線。在呼叫methodB時,沒有一個存在的事務,所以獲得一個新的連線,開啟了一個新的事務。   情形二:巢狀呼叫:methodA 的事務傳播行為和methodB的事務傳播行為都是required,如下:
<span style="white-space:pre">	</span><span style="font-family:KaiTi_GB2312;">//事務屬性 PROPAGATION_REQUIRED 
<span style="white-space:pre">	</span>methodA{ 
<span style="white-space:pre">		</span>…… 
<span style="white-space:pre">		</span>methodB(); 
<span style="white-space:pre">		</span>…… 
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>//事務屬性 PROPAGATION_REQUIRED 
<span style="white-space:pre">	</span>methodB{ 
   <span style="white-space:pre">		</span>…… 
<span style="white-space:pre">	</span>}</span>
 等價於
<span style="font-family:KaiTi_GB2312;">main{ 
<span style="white-space:pre">	</span>Connection con = null; 

<span style="white-space:pre">	</span>try{
<span style="white-space:pre">		</span>con = getConnection(); 
    <span style="white-space:pre">		</span>methodA(); 
<span style="white-space:pre">		</span>con.commit(); 
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>catch(RuntimeException ex){ 
<span style="white-space:pre">		</span>con.rollback(); 
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>finally{ 
  <span style="white-space:pre">		</span>closeCon(); 
<span style="white-space:pre">	</span>}  
} </span>
   如上:呼叫MethodA時,環境中沒有事務,所以開啟一個新的事務.當在MethodA中呼叫MethodB時,環境中已經有了一個事務,所以methodB就加入當前事務,mehtodB不會再去開啟一個新的事物。

 PROPAGATION_SUPPORTS           如果存在一個事務,支援當前事務。如果沒有事務,則非事務的執行。但是對於事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
<span style="font-family:KaiTi_GB2312;font-size:18px;">//事務屬性 PROPAGATION_REQUIRED 
methodA(){ 
  methodB(); 
}
//事務屬性 PROPAGATION_SUPPORTS 
methodB(){ 
  …… 
}</span>
 如上:單純的呼叫methodB時,methodB方法是非事務的執行的,以為外層,我們沒有新增任何的事務,但是當呼叫methdA時,在methodA中呼叫methodB,因為methodA的事務傳播行為是required,那麼methodB則加入了methodA的事務中執行。

PROPAGATION_MANDATORY

如果已經存在一個事務,支援當前事務。如果沒有一個活動的事務,則丟擲異常。   

<span style="font-family:Times New Roman;font-size:18px;">    //事務屬性 PROPAGATION_REQUIRED 
    methodA(){ 
  <span style="white-space: pre;">	</span>methodB(); 
    }</span>
<span style="font-family:Times New Roman;font-size:18px;">    //事務屬性 PROPAGATION_MANDATORY 
    methodB(){ 
    <span style="white-space: pre;">	</span>…… 
    }</span>

如上:當單獨呼叫methodB時,因為當前沒有一個活動的事務,則會丟擲異常throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");當呼叫methodA時,methodB則加入到methodA的事務中,事務地執行。

  下篇部落格,我們繼續看事務身下的四個傳播行為。