編程式事務和聲明式事務淺析

事務管理

在spring中,事物管理一般分爲兩類,編程式事務管理聲明式事務管理
編程式事務管理,一般我們使用TransactionTemplate來實現。

聲明式事物管理本質上是spring AOP的實現,對目標方法進行攔截,在目標方法之前加入事務,在執行完目標方法之後根據執行情況,進行回滾或者提交兩種操作。

下面分別介紹兩種方式的實現
 

編程式事務管理

首先是xml配置

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
  </bean>

這裏配置事務管理器的時候spring爲不同的orm框架實現了不同的platformTransactionManager接口實現

事務 orm框架
org.springframework.jdbc.datasource.DataSourceTransaction spring jdbc和ibatis
org.springframework.orm.hibernate3.Hibernate.TransactionManager hibernate3.0
org.springframework.orm.jpa.JpaTransactionManager spring data JPA
org.springframework.jdo.JdoTransactionManager 持久化機制Jdo
org.springframework.transaction.jta.JtaTransactionManager 使用JTA

常用的主要是上面兩種

 
使用時

this.getTransactionTemplate().execute(new TransactionCallback()){
        public Object doInTransaction(TransactionStatus arg0){
        操作數據庫語句a
        操作數據庫語句b       
}
}

 

聲明式事務管理

它主要是基於AOP實現,在使用時首先配置xml

 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
  </bean>

<tx:annotation-driven transaction-manager="transactionManager">

這要我們就可以直接在代碼中使用@Transactional註解來開啓事務

    @Transactional
    public void deleteUser(Long userId) throws VaException {
          //操作數據庫語句a
          //操作數據庫語句b
    }

此時如果中途發生異常,已執行的操作會回滾。

 

springboot使用事務註解@Transactional

springboot使用事務,只需要在類或者方法上標註@Transactional即可。springboot會根據我們使用的orm框架自動配置合適的事務管理器。

但是需要注意的是springboot中使用@Transactional可能失效的問題:
1.Spring 只會回滾運行時、未檢查異常(繼承自 RuntimeException 的異常)或者 Error和未被catch的異常 這是由於spring底層實現transactionTemplate決定的看源碼

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
        } else {
            TransactionStatus status = this.transactionManager.getTransaction(this);

            Object result;
            try {
                result = action.doInTransaction(status);
            } catch (Error | RuntimeException var5) {     //錯誤和運行期異常
                this.rollbackOnException(status, var5);
                throw var5;
            } catch (Throwable var6) {
                this.rollbackOnException(status, var6);
                throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
            }

            this.transactionManager.commit(status);
            return result;
        }
    }

 
2.@Transactional 註解只能應用到 public 方法纔有效

所以當你有checked類型的異常時,你可以通過設置屬性來是註解生效(可以是一個或者多個)
如@Transactional(rollbackFor=RuntimeException.class)
還有如下一些常用參數:
readOnly: 設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false

noRollbackFor:設置不需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,不進行事務回滾

propagation:設置事務的傳播行爲

isolation:設置底層數據庫的事務隔離級別,事務隔離級別用於處理多事務併發的情況,通常使用數據庫的默認隔離級別即可。

timeout :事務的超時時間,默認值爲-1(表示不限時間)。如果超過該時間限制但事務還沒有完成,則自動回滾事務,單位爲second

因爲spring使用AOP技術動態代理來實現@Transactional,但是動態代理有兩種,spring如何選擇?如果一個類有頂層接口,則默認使用jdk的動態代理來代理,如果直接是一個類,則使用cglib動態代理。

 

事務的隔離級別

@Transactional(isolation = Isolation.READ_UNCOMMITTED):讀取未提交數據(會出現髒讀,
不可重複讀) 基本不使用

@Transactional(isolation = Isolation.READ_COMMITTED):讀取已提交數據(會出現不可重複讀和幻讀)

@Transactional(isolation = Isolation.REPEATABLE_READ):可重複讀(會出現幻讀)

@Transactional(isolation = Isolation.SERIALIZABLE):串行化

 

事務傳播行爲

TransactionDefinition.PROPAGATION_REQUIRED:
如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。這是默認值。

TransactionDefinition.PROPAGATION_REQUIRES_NEW:
創建一個新的事務,如果當前存在事務,則把當前事務掛起。

TransactionDefinition.PROPAGATION_SUPPORTS:
如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。

TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事務方式運行,如果當前存在事務,則把當前事務掛起。

TransactionDefinition.PROPAGATION_NEVER:
以非事務方式運行,如果當前存在事務,則拋出異常。
TransactionDefinition.PROPAGATION_MANDATORY:
如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。

TransactionDefinition.PROPAGATION_NESTED:
如果當前存在事務,則創建一個事務作爲當前事務的嵌套事務來運行;
如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。

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