事務管理
在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。