(一)電商系統的服務端開發中,常常會遇到須要同時更改多個數據源的場景,好比訂單支付系統,用戶轉帳等等。在服務器出現異常的狀況下,也須要保證數據的一致性,於是須要把對於多個數據源的修改封裝在同一個事務中進行。Spring中的事物管理包括編程式和聲明式兩種。java
(二)Spring編程式事務管理spring
1)TransactionDefinition數據庫
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; 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(); }
接口TransactionDefinition定義了事務的7種傳播行爲和4種隔離級別apache
「只讀事務」並非一個強制選項,它只是一個「暗示」,提示數據庫驅動程序和數據庫系統,這個事務並不包含更改數據的操做,那麼JDBC驅動程序和數據庫就有可能根據這種狀況對該事務進行一些特定的優化,比方說不安排相應的數據庫鎖,以減輕事務對數據庫的壓力,畢竟事務也是要消耗數據庫的資源的。 編程
可是你非要在「只讀事務」裏面修改數據,也並不是不能夠,只不過對於數據一致性的保護不像「讀寫事務」那樣保險而已。 數組
所以,「只讀事務」僅僅是一個性能優化的推薦配置而已,並不是強制你要這樣作不可性能優化
2)TransactionStatus服務器
package org.springframework.transaction; import java.io.Flushable; public interface TransactionStatus extends SavepointManager, Flushable { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); @Override void flush(); boolean isCompleted(); }
3)PlatformTransactionManager併發
package org.springframework.transaction; public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
getTransaction根據事務的定義返回一個已有的或是新建一個事務。我估計是根據事務的名稱返回一個已有的事務,不然則根據事務定義的傳播行爲、隔離級別、超時時間新建一個事務。getTransaction的實現若遇到了一個本身不支持的事務定義,則須要拋出異常。app
commit提交事務。若事務被標記爲回滾,則執行回滾;若事務是新事務,那麼提交以後會從新執行先前因生成該事務而暫停的其餘事務;事務提交前產生的異常會致使事務提交失敗。
rollback回滾事務。若先前此事務提交失敗則不能夠執行回滾操做。
直接使用PlatformTransactionManager接口的實現去進行事務管理比較麻煩,Spring提供了TransactionTemplate事務模版,該模板封裝了事物管理者生成事物、提交事物、回滾事物的操做,方便咱們在業務代碼中適用事務。因此若要使用編程式的事物管理,通常推薦使用TransactionTemplate而不是直接使用PlatformTransactionManager。
4)TransactionTemplate
package org.springframework.transaction.support; import java.lang.reflect.UndeclaredThrowableException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionSystemException; @SuppressWarnings("serial") public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private PlatformTransactionManager transactionManager; public TransactionTemplate() { } public TransactionTemplate(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) { super(transactionDefinition); this.transactionManager = transactionManager; } public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } @Override public void afterPropertiesSet() { if (this.transactionManager == null) { throw new IllegalArgumentException("Property 'transactionManager' is required"); } } @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 { logger.debug("Initiating transaction rollback on application exception", ex); try { this.transactionManager.rollback(status); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } } }
TransactionTemplate內部包含了事物管理者PlatformTransactionManager transactionManager,而且繼承了DefaultTransactionDefinition,即擁有了事物定義的信息。
<T> T execute(TransactionCallback<T> action)是TransactionTemplate內部的一個公有方法,事物的提交或回滾,以及具體的業務邏輯都在該方法中實現,該方法的參數TransactionCallback<T> action是一個接口,須要開發人員自行實現該接口的一個方法doInTransaction(TransactionStatus status)。
在execute方法中,首先經過transactionManager.getTransaction(this)開啓一個事物,獲取事物狀態status;而後具體的業務邏輯在doInTransaction(TransactionStatus status)中編寫;最後,若無任何異常,則執行事物提交的操做transactionManager.commit(TransactionStatus status),不然,捕獲異常,執行事物的回滾操做transactionManager.rollback(TransactionStatus status);在業務邏輯中,可根據具體業務須要,設置status.setRollbackOnly(),指定事物回滾。
若不須要返回值,則可使用TransactionCallbackWithoutResult代替TransactionCallback,並調用方法doInTransactionWithoutResult代替doInTransaction。
(三)Spring聲明式事務管理
聲明式事物管理是基於AOP的,即對調用方法進行攔截,在執行目標方法前開啓一個事物,在執行目標方法後根據狀況提交事物或是回滾事物。
聲明式的事物管理器有兩種,一種是經過在類、接口或方法上添加@Transactional註解,一種是經過xml配置文件。
1)@Transactional註解
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; @AliasFor("value") String transactionManager() default ""; Propagation propagation() default Propagation.REQUIRED; Isolation isolation() default Isolation.DEFAULT; int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; boolean readOnly() default false; String[] rollbackForClassName() default {}; Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; }
value | 事物管理器 |
propagation | 設置事務的傳播行爲。 @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) |
isolation | 設置底層數據庫的事務隔離級別,事務隔離級別用於處理多事務併發的狀況 |
timeout | 設置事物的超時時間,-1表明永遠不超時 |
readOnly | 設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false。@Transactional(readOnly=true) |
rollbackFo | 設置須要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。 @Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
rollbackForClassName | 設置須要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,則進行事務回滾。 @Transactional(rollbackForClassName={"RuntimeException","Exception"}) |
noRollbackFor | 設置不須要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,不進行事務回滾。 @Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName | 設置不須要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,不進行事務回滾。 @Transactional(noRollbackForClassName={"RuntimeException","Exception"}) |
2)使用xml
3)注意
(三)兩種事物管理方式的比較
使用編程式事物管理可使得事物的粒度細化到代碼塊級別,可是在不可避免地會致使業務代碼的實現和事物管理的代碼耦合。
使用聲明式事物管理能夠避免侵入式編程,不須要在業務代碼中摻瑣事務管理的代碼,只須要在配置文件中作相關的事物規則聲明,使得業務代碼不受污染,可是其封裝粒度只能到達方法級別。
(四)自動提交
默認狀況下,數據庫處於自動提交模式。每一條語句就是一個單獨的事物,該語句執行完畢後,若成功則隱式提交事物,若失敗則隱式回滾事物。可是對於正常的事物管理,是一組相關的操做處於一個事物之中,於是須要關閉數據庫的自動提交。spring會將底層鏈接的自動提交設置爲false。