1. 程式人生 > >spring 事物之一----基本概論

spring 事物之一----基本概論

Spring 事物基本概念

什麼是事物

    事務是邏輯上的一組操作,組成這組操作的各個邏輯單元,要麼一起成功,要麼一起失敗。

    簡單舉例,假設有使用者A,B的賬戶各有餘額100元,A給B轉100元,轉錢的結果:第一種結果轉賬成功,A賬戶的餘額為0元,B賬戶的餘額為200元;第二種結果轉賬失敗,A賬戶的餘額為100元,B賬戶的餘額為100元;事物就是用來保證在轉賬的過程中不會出現A賬戶的餘額為100元,B賬戶的餘額為200元。或是A賬戶的餘額為0元,B賬戶的餘額為100元。

事務特性(ACID)

原子性 (Atomicity) :事務的不可分割性
    A給B轉賬100元,A-100成功,B+100成功;A-100失敗,B+100失敗;兩個操作必須保持一致,不可再分。

一致性 (Consistency):事務的執行的前後資料的完整性保持一致
    A,B賬戶各100元,A給B轉賬100元,不管成功或者失敗,A,B賬戶合計都為200元;此為強一致性; 題外話(最終一致性,有興趣的話可以看看分散式事物),可以在某個時間視窗賬戶共計不為200元,但是最終結果為200元。

隔離性 (Isolation) :一個事務執行的過程中,不應該受到其他事務的干擾
    A給B轉賬100元過程中,叫做事物1,有個操作查詢A餘額,叫做事物2,事物2查詢A餘額的只會0元或者100元,也就是說只能查詢到事物1執行事物之前或者之後的狀態,不會查詢到事情1執行過程中的中間狀態。

永續性 (Durability) :事務一旦結束,資料就持久到資料庫
    A,B賬戶各100元,A給B轉賬100元,A-100成功,B+100成功;A的賬戶變成0元,B的賬戶變成200元,最終會在資料庫做資料持久化。

事物隔離級別

如果不考慮事物隔離性,多個事物在執行情況下將會出現如下安全性問題:

1.髒讀 : 一個事務讀到了另一個事務的未提交的資料 。
    事物1做update操作未提交,事物2做select操作,此時如果事物1回滾,那麼事物2就讀取了事物1操作後的結果。導致髒讀。

2.不可重複讀 : 一個事務讀到了另一個事務已經提交的 update 的資料導致多次查詢結果不一致.。
    事物1第一次做select操作,此時事物2做update操作並提交,事物1第二次做select操作,發現和第一次查詢的結果不一樣。

3.虛幻讀 : 一個事務讀到了另一個事務已經提交的 insert 的資料導致多次查詢結果不一致。
    事物1做update操作將賬戶的餘額全部改為0,並進行第一次select操作,發現餘額都為0,此時事物2插入一條餘額為100元的記錄,事物1做第二次操作,發現賬戶還有大於0的資料,有點虛幻的感覺,明明已經全部餘額改為0了。

 **那麼問題來了,如何來解決上述情況呢,其實很簡單我們通過設定事務隔離級別**

事務隔離級別(5種)
DEFAULT
預設的隔離級別,使用資料庫預設的事務隔離級別.

未提交讀(Read Uncommitted)
最低的隔離級別,如果一個事務已開始寫資料,則另外一個事務不允許同時進行寫操作,但允許其他事務讀此行資料。髒讀,不可重複讀,虛讀都有可能發生 。

已提交讀(Read Committed)
讀取資料的事務允許其他事務繼續訪問該行資料,但是未提交的寫事務將會禁止其他事務訪問該行,避免髒讀。但不可重複讀和虛讀有可能發生。

可重複讀(Repeatable Read)
讀取資料的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務,相當於程式select…for update動作,可避免髒讀和不可重複讀,但虛讀有可能發生。

序列化讀(Serializable)
事務序列執行,不能併發執行。相當於每次執行之前先鎖全表,雖可避免以上所有讀問題,但效能低下。

Mysql 預設:可重複讀
Oracle 預設:讀已提交

事務的傳播行為

PROPAGATION_REQUIRED 支援當前事務,如果不存在 就新建一個(預設)
PROPAGATION_REQUIRES_NEW 如果有事務存在,掛起當前事務,建立一個新的事務
PROPAGATION_NESTED 如果當前事務存在,則巢狀事務執行
PROPAGATION_SUPPORTS 支援當前事務,如果不存在,就不使用事務
PROPAGATION_NOT_SUPPORTED 以非事務方式執行,如果有事務存在,掛起當前事務
PROPAGATION_MANDATORY 支援當前事務,如果不存在,丟擲異常
PROPAGATION_NEVER 以非事務方式執行,如果有事務存在,丟擲異常

事務的管理方式

spring支援程式設計式事務管理和宣告式事務管理兩種方式。
1.程式設計式事務管理使用TransactionTemplate或者直接使用底層PlatformTransactionManager。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
TransactionStatus status = transactionManager.getTransaction(def);
		try {
			String insertSql = this.getInsertSql(newItems);
			List<Object[]> batchArgs = this.getInsertValueList(newItems);
			jdbcTemplate.batchUpdate(insertSql, batchArgs);
		} catch (Exception e) {
				// 事務回滾,一條條執行
				transactionManager.rollback(status);
				throw e;
		}
		transactionManager.commit(status);

2.宣告式事務管理也有兩種常用的方:

一種是基於tx和aop名字空間的xml配置檔案

<!-- 1.宣告式事務,基於tx和aop名字空間的xml配置檔案 -->
    <bean id="web_transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<tx:advice id="web_txAdvice" transaction-manager="web_transactionManager">
		<tx:attributes>
		   <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class" />
		    <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
     		<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
		</tx:attributes>
	</tx:advice>
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
                      expression="execution(* com.kook.web.base.dao.*.*(..))" />
        <aop:advisor advice-ref="web_txAdvice"
                     pointcut-ref="interceptorPointCuts" />
    </aop:config>

一種就是基於@Transactional註解。

<!--2.宣告式事務,基於@Transactional註解-->
    <tx:annotation-driven transaction-manager="txManager" />
     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource" />
     </bean>

@Transactional註解

@Transactional屬性

屬性 型別 描述
value String 指定使用的事務管理器,可選的
propagation enum: Propagation 可選的事務傳播行為設定(7種)
isolation enum: Isolation 可選的事務隔離級別設定(5種)
readOnly boolean 讀寫或只讀事務,預設讀寫
timeout int 事務超時時間設定(單位秒)
rollbackFor Class物件陣列,繼承自Throwable 導致事務回滾的異常類陣列
rollbackForClassName 類名陣列,繼承自Throwable 導致事務回滾的異常類名字陣列
noRollbackFor Class物件陣列,繼承自Throwable 不會導致事務回滾的異常類陣列
noRollbackForClassName 類名陣列,必須繼承自Throwable 不會導致事務回滾的異常類名字陣列

@Transactional用法
[email protected] 可以用於介面、介面方法、類以及類方法上,一般情況不要在介面和介面方法上使用該註解
[email protected] 註解只能被應用到 public 方法上,如果你在 protected、private 或者預設可見性的方法上使用 @Transactional 註解,註解將會被忽略,也不會丟擲任何異常。
3.預設情況下,只有來自外部的方法呼叫才會被AOP代理捕獲,也就是,類內部方法呼叫本類內部的其他方法並不會引起事務行為