Spring持久化支持(一)-Spring事務管理

事務管理的目的是保證數據操作的事務性(原子性、一致性、隔離性、持久性ACID),脫離了事務性,DAO照樣可以順利地進行數據操作。

事務是一系列的動作, 它們被當做一個單獨的工作單元. 這些動作要麼全部完成, 要麼全部不起作用

 

Spring事務管理是Spring AOP技術的應用。

 

Spring對事務管理的支持

Spring爲事務管理提供了一致的編程模板,在高層次建立了統一的事務抽象。

不管選擇Spring JDBC、Hibernate、JPA還是MyBatis,Spring都可讓用戶用統一的編程模型進行事務管理。

 

Spring爲事務管理提供了事務模板類TransactionTemplate。

通過TransactionTemplate並配合使用事務回調TransactionCallback指定具體的持久化操作,就可通過編程方式實現事務管理,無須關注資源獲取、複用、釋放、事務同步和異常處理等操作

 

事務管理作爲一個切面織入目標業務方法的周圍,業務方法完全從事務代碼中解脫出來,代碼的複雜度大大降低。

被織入的事務代碼基於Spring事務同步管理器進行工作,事務同步管理器維護着業務類對象線程相關的資源。DAO類需要利用資源獲取工具訪問底層數據連接,或者直接建立在相應的持久化模板類的基礎上。

 

要了解它們的內部機制,就必須事先了解ThreadLocal的工作機制。

 

Spring的事務配置主要提供兩方面的信息:

其一,切點信息,用於定位實施事務切面的業務類方法;

其二,控制事務行爲的事務屬性,這些屬性包括事務隔離級別、事務傳播行爲、超時時間、回滾規則等。

 

Spring通過aop/tx Schema命名空間和@Transactional註解技術,大大簡化了聲明式事務配置的難度。同時,瞭解基於TransactionProxyFactoryBean代理類定義聲明式事務的工作機制,有助於理解事務增強的內部過程。

 

Spring事務管理:(優點)Spring-tx

提供統一的API接口支持不同的資源:具體的事務源不一樣也沒問題

提供聲明式事務管理:事務代碼不需要嵌入代碼,AOP

方便與Spring框架繼承

多個資源(數據源)的事務管理、同步

 

 

Spring事務管理的亮點在於聲明式事務管理。

Spring允許通過聲明方式,在IoC配置中指定事務的邊界和事務屬性,Spring自動在指定的事務邊界上應用事務屬性。聲明式事務是EJB烜赫一時的技術,Spring讓這種技術平民化,甚至可以說,Spring的聲明事務比EJB的更爲強大

 

 

核心接口

Spring事務管理SPI (Service Provider Interface)的抽象層主要包括3個接口,分別是 PlatformTransactionManager、TransactionDefinition 和 TransactionStatus,位於org.springframework.transaction包中

Spring事務管理涉及的接口的聯繫如下:

根據 TransactionDefinition 提供的事務屬性配置信息創建事務,並用TransactionStatus描述這個激活事務的狀態

 

PlatformTransactionManager通過TransactionDefinition設置事務相關信息管理事務。

管理事務過程中,產生一些事務狀態:狀態由TransactionStatus

 

PlatformTransactionManager:事務管理接口

org.springframework.transaction.PlatformTransactionManager接口是Spring核心事務管理器。

事務的開啓、提交、回滾等由具體的事務管理器實現

事務只能被提交或回滾(或回滾到某個保存點後提交)

public interface PlatformTransactionManager {
   TransactionStatus
getTransaction(TransactionDefinition definition) throws TransactionException; //根據事務定義信息從事務環境中返回一個己存在的事務,或者創建一個新的事務,並用TransactionStatus描述這個事務的狀態
  
void commit(TransactionStatus status) throws TransactionException; //:根據事務的狀態提交事務。如果事務狀態已經被標識爲rollback-only,則該方法將執行一個回滾事務的操作。
  
void rollback(TransactionStatus status) throws TransactionException; //將事務回滾。當 commit()方法拋出異常時,rollback()方法會被隱式調用。
}

 

Spring不直接管理事務,而是提供了多種事務管理器,將事務管理的職責委託給底層具體的持久化實現框架來完成

Spring事務管理的優點:爲不同的事務API提供一致的編程模型,如JTA、JDBC、Hibernate、JPA。

 

Spring爲不同的持久化框架提供了不同的PlatformTransactionManager接口實現。

PlatformTransactionManager實現類

說明

org.springframework.jdbc.datasource.

DataSourceTransactionManager

使用spring JDBC或mybatis進行持久化數據時使用

org.springframework.orm.hibernate5.

HibernateTransactionManager

使用Hibernate5版本進行持久化數據

org.springframework.orm.jpa.JpaTransactionManager

Jpa時使用

org.springframework.orm.jdo.JdoTransactionManager

Jdo時使用

org.springframework.transaction.jta.

JtaTransactionManager

使用JTA實現來管理事務,在一個事務跨越多個資源時必須使用

 

事務管理器以普通的 Bean 形式聲明在 Spring IOC 容器中

實現事務管理,首先要在Spring中配置好相應的事務管理器,爲事務管理器指定數據資源及一些其他事務管理控制屬性

 

PlatformTransactionManager提供了統一的API

AbstractPlatformTransactionManager抽象類源碼:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager,Serializable {
@Override

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

   Object transaction = doGetTransaction();  // 子類對象不同,所以用Object接受。歸子類去實現
// Cache debug flag to avoid repeated checks.

   boolean debugEnabled = logger.isDebugEnabled();

   if (definition == null) { // Use defaults if no transaction definition given.

      definition = new DefaultTransactionDefinition();

   }

   if (isExistingTransaction(transaction)) {  // 是否是已存在的事務
     // Existing transaction found -> check propagation behavior to find out how to behave.

      return handleExistingTransaction(definition, transaction, debugEnabled);

   }

   // Check definition settings for new transaction.

   if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {  //  是否超時

      throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());

   }

   // No existing transaction found -> check propagation behavior to find out how to proceed.

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

      throw new IllegalTransactionStateException(

            "No existing transaction found for transaction marked with propagation 'mandatory'");

   } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

      SuspendedResourcesHolder suspendedResources = suspend(null);

      try {

         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

         DefaultTransactionStatus status = newTransactionStatus(

               definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

         doBegin(transaction, definition);

         prepareSynchronization(status, definition);

         return status;

      }   catch (RuntimeException ex) {

         resume(null, suspendedResources);

         throw ex;

      catch (Error err) {

         resume(null, suspendedResources);

         throw err;

      }

   }  else {

      // Create "empty" transaction: no actual transaction, but potentially synchronization. 

      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

      return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);

   }

}
// 子類實現的模板方法

protected abstract Object doGetTransaction() throws TransactionException;

protected boolean isExistingTransaction(Object transaction) throws TransactionException {
  
return false;
}

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {

// 判斷事務傳播屬性,不同的傳播屬性不同的行爲
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
     
throw new IllegalTransactionStateException(
           
"Existing transaction found for transaction marked with propagation 'never'");
  
}
  
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
      Object suspendedResources = suspend(transaction)
;
      boolean
newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return
prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);
  
}
  
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
      SuspendedResourcesHolder suspendedResources = suspend(transaction)
;
      try
{
        
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        
DefaultTransactionStatus status = newTransactionStatus(
               definition
, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        
doBegin(transaction, definition);
        
prepareSynchronization(status, definition);
         return
status;
     
}   catch (RuntimeException beginEx) {
         resumeAfterBeginException(transaction
, suspendedResources, beginEx);
         throw
beginEx;
     
} catch (Error beginErr) {
         resumeAfterBeginException(transaction
, suspendedResources, beginErr);
         throw
beginErr;
     
}
   }
  
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 (useSavepointForNestedTransaction()) {
         
// Create savepoint within existing Spring-managed transaction,
         // through the SavepointManager API implemented by TransactionStatus.
         // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
        
DefaultTransactionStatus status =
               prepareTransactionStatus(definition
, transaction, false, false, debugEnabled, null);
        
status.createAndHoldSavepoint();
         return
status;
     
} else {
        
// Nested transaction through nested begin and commit/rollback calls.
         // Usually only for JTA: Spring synchronization might get activated here
         // in case of a pre-existing JTA transaction.
        
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        
DefaultTransactionStatus status = newTransactionStatus(
               definition
, transaction, true, newSynchronization, debugEnabled, null);
        
doBegin(transaction, definition);
        
prepareSynchronization(status, definition);
         return
status;
     
}
   }

// 判斷事務隔離級別 // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
   if (isValidateExistingTransaction()) {
     
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
         Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel()
;
         if
(currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
            Constants isoConstants = DefaultTransactionDefinition.
constants;
            throw new
IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " +(currentIsolationLevel != null ?isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :"(unknown)"));
        
}
      }
     
if (!definition.isReadOnly()) {  // 是否只讀
         if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
           
throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition +
"] is not marked as read-only but existing transaction is");
        
}
      }
   }
  
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
   return
prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

protected final DefaultTransactionStatus prepareTransactionStatus( TransactionDefinition definition, Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, Object suspendedResources) {
   DefaultTransactionStatus status = newTransactionStatus(definition
, transaction, newTransaction, newSynchronization, debug, suspendedResources);
  
prepareSynchronization(status, definition);
   return
status;
}

/**
 * Create a TransactionStatus instance for the given arguments.
 */

protected DefaultTransactionStatus newTransactionStatus( TransactionDefinition definition, Object transaction,boolean newTransaction,boolean newSynchronization,boolean debug, Object suspendedResources) {
  
boolean actualNewSynchronization = newSynchronization &&
         !TransactionSynchronizationManager.isSynchronizationActive()
;
   return new
DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization,
        
definition.isReadOnly(), debug, suspendedResources);
}
/*** Initialize transaction synchronization as appropriate. */
protected void prepareSynchronization(DefaultTransactionStatus status,TransactionDefinition definition) {
  
if (status.isNewSynchronization()) {
      TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction())
;
     
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
            definition.getIsolationLevel() != TransactionDefinition.
ISOLATION_DEFAULT ?
                  definition.getIsolationLevel() :
null);
     
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
     
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
     
TransactionSynchronizationManager.initSynchronization();
  
}
}

 

各個平臺框架實現事務管理的機制:

1)DataSourceTransactionManager - JDBC事務

DataSourceTransactionManager是通過調用java.sql.Connection來管理事務,而Connection是通過DataSource獲取到的。通過調用連接的commit()方法來提交事務,同樣,事務失敗則通過調用rollback()方法進行回滾。

如果使用Spring JDBC或MyBatis,由於它們都基於數據源的Connection訪問數據庫, 只要在Spring中配置DataSourceTransactionManager就可以。

XML配置:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

</bean>

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p: dataSource-ref=“dataSource”/>

 

DataSourceTransactionManager源碼:

doGetTransaction()//從ThreadLocal中獲取一個Connection(相互對立的)

doBegin()         //開啓事務

// 執行業務邏輯

// 根據業務邏輯的執行結果判斷是否要提交還是回滾

doCommit()//提交

doRallback() // 回滾

 

2)HibernateTransactionManager - Hibernate事務

HibernateTransactionManager實現細節:將事務管理的職責委託給org.hibernate.Transaction對象,Transaction是從Hibernate Session中獲取到的。當事務成功完成時,HibernateTransactionManager會調用Transaction對象的commit(),反之,會調用rollback()。

Hibernate使用org.hibemate.Session封裝Connection,所以要一個能夠創建Session的SessionFactory

在配置事務管理器時,需要引入sessionFactory屬性。

    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

        <property name="sessionFactory" ref="sessionFactory" />

    </bean>

 

3)JpaTransactionManager - Java持久化API事務(JPA)

JpaTransactionManager只需要裝配一個JPA實體管理工廠(javax.persistence.EntityManagerFactory接口的任意實現)。JpaTransactionManager將與由工廠所產生的JPA EntityManager合作來構建事務。

JPA 通過 javax.persistence.EntityTransaction 管理 JPA 的事務,EntityTransaction 對象可通過 javax.persistence.EntityManager#getTransaction()方法獲得,而 EntityManager 又通過一個工廠類方法 javax.persistence.EntityManagerFactory#createEntityManager()獲取。

在底層,JPA依然通過JDBC的Connection的事務方法完成最終的控制。因此,要配置一個JPA事務管理器,必須先提供一個DataSource,然後配置一個EntityManagerFactory,最後才配置JpaTransactionManager

 

Java持久化API是Java持久化標準。如果用JPA則需用JpaTransactionManager來處理事務。

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

        <property name="sessionFactory" ref="sessionFactory" />

    </bean>

<bean id="entityManagerFactory" class=norg.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 

p:dataSource_ref="dataSource”/>

</bean>

<bean id="transactionManager" class=" org.springframework.orm.jpa.JpaTransactionManager "   

p:entityManagerFactory-ref="entityManagerFactory"/>

 

4)JtaTransactionManager - Java原生API事務

JtaTransactionManager將事務管理的責任委託給javax.transaction.UserTransaction和javax.transaction.TransactionManager對象,事務成功完成通過UserTransaction.commit()方法提交,事務失敗通過UserTransaction.rollback()方法回滾。

 

如果用其他持久化技術,或跨越多個事務管理源(如兩或是多個不同的數據源),需要使用JtaTransactionManager:

JtaTransactionManager不需要知道DataSource和其他特定的資源,因爲它引用容器提供的全局事務管理

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

        <property name="transactionManagerName" value="java:/TransactionManager" />

    </bean>

 

 

5)JmsTransactionManager – 使用各種消息中間件

 

 

 

 

事務管理器接口PlatformTransactionManager通過getTransaction(TransactionDefinition definition)得到事務, TransactionDefinition類定義了一些基本的事務屬性。

 

TransactionDefinition:事務的定義

描述事務的隔離級別、超時時間、是否爲只讀事務和事務傳播規則等控制事務具體行爲的事務屬性,這些事務屬性可通過XML配置或註解描述提供,也可通過手工編程的方式設置。

事務屬性是事務的一些基本配置,描述了事務策略如何應用到方法上。事務屬性包含了5個方面

public interface TransactionDefinition {
   // 傳播行爲

   int PROPAGATION_REQUIRED = 0;
   int PROPAGATION_SUPPORTS = 1;
   int PROPAGATION_MANDATORY = 2;
   int PROPAGATION_REQUIRES_NEW = 3;
   int PROPAGATION_NOT_SUPPORTED = 4;
   int PROPAGATION_NEVER = 5;
   int PROPAGATION_NESTED = 6;

// 事務隔離級別(Spring提供多一個Default
   int ISOLATION_DEFAULT = -1;
   int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
   int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
   int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
   int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

// 超時
   int TIMEOUT_DEFAULT = -1;
   int getPropagationBehavior();    // 返回事務的傳播行爲
   int getIsolationLevel();   // 返回事務的隔離級別,事務管理器根據它來控制另外一個事務可以看到本事務內的哪些數據
   int getTimeout();           // 返回事務必須在多少秒內完成
   boolean isReadOnly();       // 事務是否只讀,事務管理器能夠根據這個返回值進行優化,確保事務是隻讀的
   String getName();
}

1)事務傳播行爲(規則):Spring定義了7種傳播屬性

傳播行爲:當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播

如:方法可能繼續在現有事務中運行,也可能開啓一個新事務,並在自己的事務中運行

規定了事務方法和事務方法發生嵌套調用時事務如何進行傳播、

 

1.PROPAGATION_REQUIRED(常見的方式,默認)

當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。沒有事務則新建一個事務

如果有事務在運行,當前的方法就在這個事務內運行,否則,新建一個事務,並在自己的事務內運行,。

 

2.PROPAGATION_SUPPORTS

支持當前事務。如果當前沒有事務,則以非事務方式執行

如果有事務在運行,當前的方法就在這個事務內運行,否則它不可以運行在事務中

3.PROPAGATION_MANDATORY

該方法必須在事務中運行如果當前事務不存在,則會拋出一個異常

當前的方法必須運行在事務內部,如果沒有正在運行的事務,就拋出異常

 

4.PROPAGATION_REQUIRES_NEW

新建事務。如果當前存在事務,則把當前事務掛起。表示當前方法必須運行在它自己的事務中。一個新的事務將被啓動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager

表示該方法必須啓動一個新事務, 並在自己的事務內運行. 如果有事務在運行, 就應該先掛起它

當前的方法必須啓動新事務,並在它自己的事務內運行,如果有事務正在運行,應該將它掛起

 

5.PROPAGATION_NOT_SUPPORTED

以非事務方式執行操作。如果當前存在事務,則把當前事務掛起。表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager

當前的方法不應該運行在事務內部,如果有運行的事務,則將它掛起

6.PROPAGATION_NEVER

以非事務方式執行。如果當前存在事務在運行,則拋出異常

當前的反方不應該運行在事務中,如果有運行的事務,則拋出異常

7.PROPAGATION_NESTED

如果當前存在事務,則在嵌套事務內執行:如果當前沒有事務,則執行與
PROPAGATION_REQUIRED 類似的操作。嵌套的事務可以獨立於當前事務進行單獨地提交或回滾。如果當前事務不存在,那麼其行爲與PROPAGATION_REQUIRED一樣。注意各廠商對這種傳播行爲的支持是有所差異的。可以參考資源管理器的文檔來確認它們是否支持嵌套事務

 

如果有事務在運行,當前的方法就應該在這個事務的嵌套事務內運行,否則就啓動一個新的事務,並在他自己的事務內運行

 

注:在使用PROPAGATION_NESTED時,底層的數據源必須基於JDBC3.0,並且實現者需要支持保存點事務機制

 

 

2)事務隔離級別

併發若無好的隔離級別,將導致髒讀、不可重複讀、幻讀等問題

Spring定義的隔離級別和java.sql.Connection接口的四個隔離級別同名。

1. ISOLATION_READ_UNCOMMITTED

 

2. ISOLATION_READ_COMMITTED

 

3. ISOLATION_REPEATABLE_READ

 

4. ISOLATION_SERIALIZABLE

 

5. ISOLATION_DEFAULT

表示使用底層數據庫的默認隔離級別

 

 

由於事務可以在行和表上獲得鎖,  因此長事務會佔用資源, 並對整體性能產生影響.

如果一個事物只讀取數據但不做修改, 數據庫引擎可以對這個事務進行優化.

 

3)事務超時

事務在超時前能運行多久,超過時間後,事務被回滾。有些事務管理器不支持事務過期的功能,這時,如果設置TIMEOUT_DEFAULT之外的其他值,則將拋出異常

超時事務屬性: 事務在強制回滾之前可以保持多久. 這樣可以防止長期運行的事務佔用資源.

 

4)只讀

只讀事務不修改任何數據,資源事務管理者可以針對可讀事務應用一些優化措施,提高運行性能。只讀事務在某些情況下(如使用Hibernate時)是一種非常有用的優化,試圖在只讀事務中更改數據將引發異常。

只讀事務屬性: 表示這個事務只讀取數據但不更新數據, 這樣可以幫助數據庫引擎優化事務

 

5)回滾事務屬性

默認情況下只有未檢查異常(RuntimeException和Error類型的異常)會導致事務回滾. 而受檢查異常不會.

事務的回滾規則可以通過 @Transactional 註解的 rollbackFor 和 noRollbackFor 屬性來定義. 這兩個屬性被聲明爲 Class[] 類型的, 因此可以爲這兩個屬性指定多個異常類.

 

屬性配置與使用:

註解@Transaction:

@Transactional相關屬性:

Propagation:定義事務傳播屬性 org.springframework.transaction.annotation.Propagation

Isolation:設置隔離級別        org.springframework.transaction.annotation.Isolation

readOnly:設置只讀屬性          @Transactional(readOnly=true)

timeout:設置超時時間。單位爲秒 @Transactional(timeout=10)

rollbackFor:設置異常回滾策略    @Transactional(rollbackFor={SQLException.class})) 多個異常之間可用逗號分隔

noRollbackFor:設置異常不回滾策略

@Transactional(propagation=Propagation.REQUIRES_NEW
      isolation=Isolation.READ_COMMITTED, //事務隔離級別。讀與提交
     
readOnly=false,  //只讀
     
//rollbackFor = ,
      //noRollbackFor = {UserAccountException.class},//
對於這種異常不回滾
     
timeout=3)   //超時就回滾

 

@Transactional在類上面註解:適用於所有public的方法

@Transactional在方法上註解:將覆蓋類級別註解

 

使用不同的事務管理器:

Xml中定義不同的事務管理器:

每個事務管理器可以綁定一個獨立的數據源。

 

Xml配置文件配置:

在 Spring 2.x 事務通知中,在 <tx:method> 元素中設定傳播事務屬性、隔離級別、回滾策略(不止一種異常則用逗號隔開)、只讀屬性和超時時間。

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <
tx:attributes>
       
<!-- 根據方法名指定事務的屬性 -->
       
<tx:method name="purchase"

propagation="REQUIRES_NEW"
       
isolation="READ_COMMITTED"
       
rollback-for="java.io.IOException,java.sql.SQLException"
       
no-rollback-for="java.lang.ArithmeticException"
       
timeout="30"
       
read-only="true"/>
        <
tx:method name="get*" read-only="true"/>
        <
tx:method name="find*" read-only="true"/>
        <
tx:method name="*"/>
    </
tx:attributes>
</
tx:advice>

 

 

TransactionStatus:代表一個事務的具體運行狀態

事務管理器可通過該接口獲取事務運行期的狀態信息,也可通過該接口間接回滾事務,它相比於在拋出異常時回滾事務的方式更具可控性。

調用PlatformTransactionManager的getTransaction()的方法得到的是TransactionStatus接口的一個實現

TransactionStatus 擴展了 SavepointManager 接口。

public interface TransactionStatus extends SavepointManager, Flushable {
   boolean isNewTransaction();//當前事務是否是一個新的事務,當前事務是已經存在的事務返回false,或當前操作未運行在事務環境中
   boolean hasSavepoint(); //判斷當前事務是否在內部創建了一個保存點,該保存點是爲了支持Spring的嵌套事務而創建的
   void setRollbackOnly();//將當前事務設置爲rollback-only。通過該標識通知事務管理器只能將事務回滾,事務管理器將通過顯式調用回滾命令或拋出異常的方式回滾事務
   boolean isRollbackOnly();//判斷當前事務是否己經被標識爲rollback-only只回滾
   @Override
  
void flush();
   boolean isCompleted();//判斷當前事務是否己經結束(己經提交或回滾)
}

 

該接口繼承於SavepointManager接口

SavepointManager接口基於JDBC 3.0保存點的分段事務控制能力提供了嵌套事務的機制。

public interface SavepointManager {
   Object createSavepoint() throws TransactionException; //創建一個保存點對象,以便在後面可以利用
   void rollbackToSavepoint(Object savepoint) throws TransactionException; //使事務回滾到特定的保存點上,被回滾的保存點將自動釋放,也可通過releaseSavepoint()釋放一個己經不用的保存點
   void releaseSavepoint(Object savepoint) throws TransactionException; //釋放一個保存點。如果事務提交,則所有的保存點會被自動釋放,無須手工清除
}

這3個方法在底層的資源不支持保存點時,都將拋出NestedTransactionNotSupportedException 異常

 

 

 

事務同步管理器:

Spring將JDBC的Connection、Hibernate的Session等訪問數據庫的連接或會話對象統稱爲資源,這些資源在同一時刻是不能多線程共享的。爲了讓DAO、Service類可能做到 singleton,

Spring事務同步管理器類org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal爲不同事務線程提供了獨立的資源副本,同時維護事務配置的屬性和運行狀態信息。

事務同步管理器是Spring事務管理的基石,不管用戶用的是編程式事務管理,還是聲明式事務管理,都離不開事務同步管理器。

Spring框架爲不同的持久化技術提供了一套從TransactionSynchronizationManager中獲取對應線程綁定資源的工具類

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

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(); ……

}

持久化技術

線程綁定資源獲取工具

Spring JDBC 或 MyBatis

org. springframework .j dbc. datasource. DataSourceU tils

Hibernate X.0

org.springframework.orm.hibemateX.SessionFactoryUtils

JPA

org.springframework.orm.jpa.EntityManagerFactoryUtils

JDO

org.springframework.orm.jdo.PersistenceManagerFactoryUtils

這些工具類都提供了靜態的方法,通過這些方法可以獲取和當前線程綁定的資源,

DataSourceUtils.getConnection(DataSource dataSource)可從指定的數據源中獲取和當前線程綁定的 Connection,

Hibernate 的 SessionFactoryUtils.getSession(SessionFactory sessionFactory,boolean allowCreate)可從指定的SessionFactory中獲取和當前線程綁定的Session

當需要脫離模板類,手工操作底層持久化技術的原生API時,就需要通過這些工具類獲取線程綁定的資源,而不應該直接從DataSource或SessionFactory中獲取。因爲後者不能獲得與本線程相關的資源,因此無法讓數據操作參與到與本線程相關的事務環境中。

這些工具類還有另外一個重要的用途:將特定異常轉換爲Spring的DAO異常

 

Spring爲不同的持久化技術提供了模板類,模板類在內部通過資源獲取工具類間接訪問TransactionSynchronizationManager中的線程綁定資源。所以,如果DAO使用模板類進行持久化操作,這些DAO就可以配置成singleton。如果不使用模板類,也可以直接通過資源獲取工具類訪問線程相關的資源。

public abstract class TransactionSynchronizationManager {

//①用於保存每個事務線程對應的Connection或Session等類型的資源
private static final ThreadLocal resources = new ThreadLocal();

//②用於保存每個事務線程對應事務的名稱

private static final ThreadLocal currentTransactionName = new ThreadLocal();

//③用於保存每個事務線程對應事務的read-only狀態

private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
//④用於保存每個事務線程對應事務的隔離級別

private static final ThreadLocal currentTransactionIsolationLevel= new ThreadLocal();

//⑤用於保存每個事務線程對應事務的激活態

private static final ThreadLocal actualTransactionActive = new ThreadLocal();

}

TransactionSynchronizationManager 將 DAO、Service 類中影響線程安全的所有“狀態”統一抽取到該類中,並用ThreadLocal進行替換,從此DAO (必須是基於模板類或資源獲取工具類創建的DAO)和Service (必須採用Spring事務管理機制)摘掉了非線程安全的帽子,完成了脫胎換骨式的身份轉變。

 

 

 

TransactionTemplate

線程安全,可在多個業務類中共享TransactionTemplate實例進行事務管理。

@SuppressWarnings("serial")
public class TransactionTemplate extends DefaultTransactionDefinition
     
implements TransactionOperations, InitializingBean {
   @Getter @Setter private PlatformTransactionManager transactionManager;
   public TransactionTemplate() {   }
   public TransactionTemplate(PlatformTransactionManager transactionManager) {
     
this.transactionManager = transactionManager;
  
}
   public TransactionTemplate(PlatformTransactionManager transactionManager,

TransactionDefinition transactionDefinition) {
     
super(transactionDefinition);
      this
.transactionManager = transactionManager;
  
}
  
@Override
  
public void afterPropertiesSet() {
     
if (this.transactionManager == null) {
        
throw new IllegalArgumentException("Property 'transactionManager' is required");
     
}
   }

// TransactionCallback 回調接口中定義需要以事務方式組織的數據訪問邏輯
   @Override
  
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 (Throwable 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;
     
}
   }

   private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
      try {
        
this.transactionManager.rollback(status);
     
} catch (TransactionSystemException ex2) {
         ex2.initApplicationException(ex);
         throw
ex2;
     
} catch (RuntimeException ex2) {
         throw ex2;
     
catch (Error err) {
         throw err;
     
}
   }
}

 

TransactionCallback

public interface TransactionCallback<T> {
   T doInTransaction(TransactionStatus status); //如果操作不會返回結果,則可用TransactionCallback的子接口 TransactionCallbackWithoutResult
}

 

 

使用TransactionTemplate

TransactionTemplate使用回調方法,把應用程序從處理取得和釋放資源中解脫出來。TransactionTemplate是線程安全的。

    TransactionTemplate tt = new TransactionTemplate(); // 新建一個TransactionTemplate

    Object result = tt.execute(

        new TransactionCallback(){ 

            public Object doTransaction(TransactionStatus status){ 

                updateOperation(); 

                return resultOfUpdateOperation(); 

            } 

    }); // 執行execute方法進行事務管理

使用TransactionCallback()可以返回一個值。如果使用TransactionCallbackWithoutResult則沒有返回值。

 

 

@Service

public class ForumServicel {

public ForumDao forumDao;

public TransactionTemplate template;

@Autowired        // 通過AOP自動注入

public void setTemplate(TransactionTemplate template) {

this.template = template;

}

public void addForum(final Forum forum) {

template.execute(new TransactionCallbackWithoutResult() {

protected void doInTransactionWithoutResult(TransactionStatus status) {  //需要在事務環境中執行的代碼

forrxmDao. addForum(forum);

});

}

}

 

 

TransactionProxyFactoryBean:Spring事務配置與使用的源頭

TransactionProxyFactoryBean會讀取配置文件中的事務屬性並構造出代理對象(proxy)

通過TransactionProxyFactoryBean,spring會返回一個代理對象,當調用配置了事務屬性的目標方法時,spring首先會判斷該方法是否是事務方法,依據是在配置文件中爲目標方法設置的事務屬性

如果目標方法是事務方法,那麼spring就會進入到事務過程中

 

@SuppressWarnings("serial")
public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean implements BeanFactoryAware {
  
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
   @Setter private
Pointcut pointcut;


   public void setTransactionManager(PlatformTransactionManager transactionManager) {
     
this.transactionInterceptor.setTransactionManager(transactionManager);
  
}
   public void setTransactionAttributes(Properties transactionAttributes) {
     
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
  
}
   public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
     
this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
  
}
   @Override
  
public void setBeanFactory(BeanFactory beanFactory) {
     
this.transactionInterceptor.setBeanFactory(beanFactory);
  
}
   @Override
  
protected Object createMainInterceptor() {
     
this.transactionInterceptor.afterPropertiesSet();
      if
(this.pointcut != null) {
        
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
     
} else { // Rely on default pointcut.
        
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
      
}
   }

   @Override
  
protected void postProcessProxyFactory(ProxyFactory proxyFactory) {
      proxyFactory.addInterface(TransactionalProxy.
class);
  
}
}

 

 

TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
   public TransactionInterceptor() {   }
   public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
      setTransactionManager(ptm)
;
     
setTransactionAttributes(attributes);  // 加入配置文件,進行解析

   }
   public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
      setTransactionManager(ptm)
;
     
setTransactionAttributeSource(tas);
  
}

// 目標方法調用前調用
   @Override
  
public Object invoke(final MethodInvocation invocation) throws Throwable {
     
// Work out the target class: may be {@code 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 ? AopUtils.getTargetClass(invocation.getThis()) : null);  // 獲取目標類
      // Adapt to TransactionAspectSupport's invokeWithinTransaction...
     
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        
@Override
        
public Object proceedWithInvocation() throws Throwable {
           
return invocation.proceed();
        
}
      })
;
  
}
   // Serialization support
  
private void writeObject(ObjectOutputStream oos) throws IOException {
     
// Rely on default serialization, although this class itself doesn't carry state anyway...
     
oos.defaultWriteObject();
     
// Deserialize superclass fields.
     
oos.writeObject(getTransactionManagerBeanName());
     
oos.writeObject(getTransactionManager());
     
oos.writeObject(getTransactionAttributeSource());
     
oos.writeObject(getBeanFactory());
  
}
  
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
     
// Rely on default serialization, although this class itself doesn't carry state anyway...
     
ois.defaultReadObject();
     
// Serialize all relevant superclass fields.
      // Superclass can't implement Serializable because it also serves as base class
      // for AspectJ aspects (which are not allowed to implement Serializable)!
     
setTransactionManagerBeanName((String) ois.readObject());
     
setTransactionManager((PlatformTransactionManager) ois.readObject());
     
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
     
setBeanFactory((BeanFactory) ois.readObject());
  
}
}

TransactionAspectSupport

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {

private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<Object, PlatformTransactionManager>(4);

private PlatformTransactionManager transactionManager;

@Getter @Setter private TransactionAttributeSource transactionAttributeSource;  // 一個方法對應事務的信息的封裝,就是封裝了TransactionAttribute

public void setTransactionAttributes(Properties transactionAttributes) {

   NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();//適配的TransactionAttribute

   tas.setProperties(transactionAttributes);

   this.transactionAttributeSource = tas;  // 保存
}
public void setTransactionAttributeSources(TransactionAttributeSource[] transactionAttributeSources) {

   this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources);

}

protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
  
// Do not attempt to lookup tx manager if no tx attributes are set
  
if (txAttr == null || this.beanFactory == null) {
     
return getTransactionManager();
  
}
   String qualifier = txAttr.getQualifier()
;
   if
(StringUtils.hasText(qualifier)) {
     
return determineQualifiedTransactionManager(qualifier);
  
} else if (StringUtils.hasText(this.transactionManagerBeanName)) {
     
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
  
} else {
      PlatformTransactionManager defaultTransactionManager = getTransactionManager()
;
      if
(defaultTransactionManager == null) {
         defaultTransactionManager =
this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
         if
(defaultTransactionManager == null) {
            defaultTransactionManager =
this.beanFactory.getBean(PlatformTransactionManager.class);
            this
.transactionManagerCache.putIfAbsent(
                 
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
        
}
      }
     
return defaultTransactionManager;
  
}
}

private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) {

   PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier);

   if (txManager == null) {

      txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, PlatformTransactionManager.class, qualifier);

      this.transactionManagerCache.putIfAbsent(qualifier, txManager);

   }

   return txManager;

}

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
  
//If the transaction attribute is null,the method is non-transactional.如果事務屬性爲空,則方法是非事務性的
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); // 一個方法配置事務後,會對應一個TransactionAttribute對象,這個對象封裝的是方法的名字和方法的屬性

獲取與目標方法所對應事務的屬性

   final PlatformTransactionManager tm = determineTransactionManager(txAttr)

   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
   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.
        
retVal = invocation.proceedWithInvocation();
     
catch (Throwable ex) {
         completeTransactionAfterThrowing(txInfo, ex); // target invocation exception
         throw ex;
     
finally {
         cleanupTransactionInfo(txInfo)
;
     
}
      commitTransactionAfterReturning(txInfo)
;
      return
retVal;
  
}
  
else {
     
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
     
try {
         Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr
,
               new
TransactionCallback<Object>() {
                 
@Override
                 
public Object doInTransaction(TransactionStatus status) {
            TransactionInfo txInfo = prepareTransactionInfo(
tm, txAttr, joinpointIdentification, status);
                     try
{
                       
return invocation.proceedWithInvocation();
                    
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();
     
}
   }
}

protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm,
TransactionAttribute txAttr, final String joinpointIdentification) {

  // If no name specified, apply method identification as transaction name.

   if (txAttr != null && txAttr.getName() == null) {    // 沒有取名字,就幫忙起名字
     txAttr = new DelegatingTransactionAttribute(txAttr) {

         @Override

         public String getName() {

            return joinpointIdentification;

         }

      };

   }

   TransactionStatus status = null;  //事務狀態
   if (txAttr != null) {

      if (tm != null) {

         status = tm.getTransaction(txAttr);

      }

   }

   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

}
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {

   TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);

   if (txAttr != null) {

      // We need a transaction for this method... 

      // The transaction manager will flag an error if an incompatible tx already exists.

      txInfo.newTransactionStatus(status);

   } else {

// The TransactionInfo.hasTransaction() method will return false. We created it only to preserve the integrity of the ThreadLocal stack maintained in this class.  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;

}

NameMatchTransactionAttributeSource

public class NameMatchTransactionAttributeSource implements TransactionAttributeSource, Serializable {
private Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>();
public void setProperties(Properties transactionAttributes) {

   TransactionAttributeEditor tae = new TransactionAttributeEditor();

   Enumeration<?> propNames = transactionAttributes.propertyNames(); // 獲取配置文件的所有配置元素

   while (propNames.hasMoreElements()) {

      String methodName = (String) propNames.nextElement();

      String value = transactionAttributes.getProperty(methodName);

      tae.setAsText(value);

      TransactionAttribute attr = (TransactionAttribute) tae.getValue();  // 這裏將set進去的get出來
      addTransactionalMethod(methodName, attr);

   }

}
public void addTransactionalMethod(String methodName, TransactionAttribute attr) {

   this.nameMap.put(methodName, attr);

}

TransactionAttributeEditor

public class TransactionAttributeEditor extends PropertyEditorSupport {

   /**

    * Format is PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2.

    * Null or the empty string means that the method is non transactional.

    * @see java.beans.PropertyEditor#setAsText(java.lang.String)

    */

   @Override

   public void setAsText(String text) throws IllegalArgumentException {  // 這裏就是對配置文件配置的事務進行解析並保存封裝到PropertyEditorSupport

      if (StringUtils.hasLength(text)) {

         // tokenize it with ","

         String[] tokens = StringUtils.commaDelimitedListToStringArray(text);

         RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();

         for (int i = 0; i < tokens.length; i++) {

            // Trim leading and trailing whitespace.

            String token = StringUtils.trimWhitespace(tokens[i].trim());

            // Check whether token contains illegal whitespace within text.

            if (StringUtils.containsWhitespace(token)) {

               throw new IllegalArgumentException("Transaction attribute token contains illegal whitespace: [" + token + "]");

            }

            // Check token type.

            if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_PROPAGATION)) {

               attr.setPropagationBehaviorName(token);

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ISOLATION)) {

               attr.setIsolationLevelName(token);

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_TIMEOUT)) {

               String value = token.substring(DefaultTransactionAttribute.PREFIX_TIMEOUT.length());

               attr.setTimeout(Integer.parseInt(value));

            else if (token.equals(RuleBasedTransactionAttribute.READ_ONLY_MARKER)) {

               attr.setReadOnly(true);

            else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_COMMIT_RULE)) {

               attr.getRollbackRules().add(new NoRollbackRuleAttribute(token.substring(1)));

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ROLLBACK_RULE)) {

               attr.getRollbackRules().add(new RollbackRuleAttribute(token.substring(1)));

            } else {

               throw new IllegalArgumentException("Invalid transaction attribute token: [" + token + "]");

            }

         }

         setValue(attr);//後續會被get出來
      } else {

         setValue(null);  // PropertyEditorSupport類中進行實現

      }

   }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章