Spring--事務小結

Spring爲我們提供了非常方便的事務管理,在不需要了解不同持久層事務處理的情況下,使用配置或註解的方式實現了事務的統一管理。這也就體現了之前所說的Spring核心AOP功能的作用。而爲了更好的使用Spring事務管理,需要了解以下知識:

一、數據庫事務相關基礎知識

1、  何爲事務

最簡單的話就是,事務內的多個SQL語句,在事務提交時,要麼都成功,要麼都失敗。必定是一個整體。事務的四個特性:

1)  原子性:組成數據庫的多個事務操作是一個不可分割的原子單位。若有失敗時,已成功的操作也被撤銷。

2)  一致性:事務操作成功後,數據庫狀態和業務規則一致。

3)  隔離性:併發執行數據操作時,不同事務擁有不同的事務空間,互不干擾。

4)  持久性:事務提交成功後,所有數據操作必須持久到數據庫內。

2、  數據併發出現的問題

1)  髒讀:事務A讀取到事務B修改但是未提交的數據。當事務B回滾後,A事務如果以之前讀到的數據操作,必定會出錯。

2)  不可重複讀:事務A讀取了兩次數據,而這兩次數據由於事務B的執行前後不一致。而數據的不一致會導致問題。

3)  幻象讀:事務A按照某查詢條件讀取到數據,這時其他事務新增操作導致新增結果同樣滿足A的查詢條件。事務A再讀取時會出現前後數據不一致。

雖然不可重複讀和幻象讀有相似之處,但是區別在於不可重複讀由於數據的更改導致,而幻象讀由於新事務提交導致。

丟失更新:

           兩個事務同時對一個數據操作,在事務互不知道的情況下,其中一個事務的操作可能會被另外一個事務操作覆蓋。分爲包裹時的回滾覆蓋和提交成功的覆蓋。

接下來,由於數據庫中定義的隔離和Spring事務定義的隔離有重複部分,所以直接介紹Spring的事務屬性。

二、Spring事務隔離

         定義了當前事務與其他事務的隔離狀態。

1、  ISOLATION_DEFAULT:

這是定義的默認隔離級別,自動採用數據庫默認的事務隔離級別。

2、  ISOLATION_READ_UNCOMMITED:

這是隔離級別最低的事務隔離。會讀取到修改過但是未提交的數據。因此會出現髒讀,不可重複讀,幻象讀。隔離級別在於處理多事務的併發問題。 

3、  ISOLATION_READ_COMMITED:

保證不會讀取修改過但是未提交的數據。避免了髒讀,但是不可重複讀和幻象讀無法避免。大部分數據庫的隔離級別。

4、  ISOLATION_REPEATABLE_READ:

保證不會修改另一個事務讀取但未提交的數據,可以避免髒讀和不可重複讀。但是帶來較多的性能損失。

5、  ISOLATION_SERIALIZABLE:

事務串行執行,性能損失最大。

三、Spring事務傳播

正常而言,給一個方法定義事務執行是十分清晰的。但是,如果在一個方法中調用了另外一個方法,那麼事務操作應該如何執行呢?接下來就是有關事務傳播的話題了:

Spring定義了其中類型的事務傳播行爲,它們規定了事務方法和事務方法發生嵌套調用時如何進行傳播:

1、  PROPAGATION_REQUIRED:

如果當前執行有事務,則加入當前事務,若沒有事務,則新建一個事務。

例:有ServiceA.methodA,執行時調用ServiceB.methodB。ServiceB.methodB的事務傳播屬性設爲REQUIRED。methodB執行時,先看當前methodA執行環境有沒有事 務,如果有,則加入A所在事務,A,B任意方法異常,統一回滾。若沒有事務,新建一個事務供B方法執行。

2、  PROPAGATION_SUPPORTS:

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

3、  PROPAGATION_MANDATORY:

如果當前執行有事務,則以事務方式進行。若沒有事務,則拋出異常。

4、  PROPAGATION_REQUIRES_NEW:

無論當前有沒有事務,都新建一個事務執行。新建的事務和舊事務分屬於兩個事務,互不相干。

再以methodA和methodB爲例。A如果有事務環境,調用到B方法時,將A所在的事務掛起,B新建一個事務,B執行完後,重新進入A的事務環境。執行過程中,如果A出現 異常,B已經提交,則不用回滾。B出現異常,A方法同樣可能提交。

5、  PROPAGATION_NOT_SUPPORTED:

如果當前執行有事務,將事務掛起後繼續執行。

6、  PROPAGATION_NEVER:

如果當前執行有事務,將事務掛起後繼續執行

7、  PROPAGATION_NESTED:

同樣新建一個事務,與REQUIRES_NEW的區別在於,它與父事務是相依的。出現異常時,回滾一致。而且有一個savePoint的選擇。

四、Spring事務配置

         配置事務大方向有三種:編程式配置(侵入代碼較嚴重,不介紹),XML配置,註解配置。

1、  XML配置:

1)  原始的proxyBean:

<bean id="transactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>	  
	</bean>
	
	<!-- 織入對象 -->
	<bean id="userServiceTarget" class="com.paditang.service.UserService"
		p:userDao-ref="userDao">
	</bean>
	<!-- 織入生成的代理對象,執行時自動處理業務邏輯 -->
	<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
		p:transactionManager-ref="transactionManager"
		p:target-ref="userServiceTarget">
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>


以上配置很容易看出是基於動態代理的實現形式。但是需要對每個業務類都進行配置,且只能對方法名定義。而且定義時IDE無法判斷輸入,容易出錯,所以不推薦。

2)  基於tx/aop命名空間:

<aop:config proxy-target-class="true">
		<aop:pointcut expression="execution(* com.paditang.service.*.*(..))" id="serviceMethod"/>
		<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/><!-- 定義切點和增強 -->
	</aop:config>
	
	<tx:advice id = "txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>


2、基於註解

只需要在service實現類上增加@Transactional註解,並在Spring配置中

<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

	<!-- 配置基於註解的聲明式事務 -->
	<tx:annotation-driven transaction-manager="transactionManager" />


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