spring 比較實用的事物管理

          事物管理:這個有點抽象,書面表達是這樣的:

 

爲了完成對數據的操作,企業應用經常要求併發訪問在多個構件之間共享的數據。這些應用在下列條件下應該維護數據的完整性(由應用的商務規則來定義): 





分佈式訪問一個單獨的數據資源,以及從一個單獨的應用構件訪問分佈式資源。 


在這種情況,可能要求在(分佈式)資源上的一組操作被當作一個工作單元(unit)。在一個工作單元中, 操作的所有部分一起成功或失敗並恢復。在下面的情況下這個問題更加複雜: 





通過一組分佈式的、訪問多個資源的數據的構件實現一個工作單元,和/或部分操作是被順序執行的或在要求協調和/或同步的並行線程中。 





在所有情況下, 都要求應用維護一個工作單元的成功或失敗。在失敗的情況下,所有資源要把數據狀態返回到以前的狀態 


(比如說,工作單元開始前的狀態)。 


事務的概念和和事務管理器(或者一個事務處理服務)在一個工作單元中的維護數據完整性,這就簡化了這樣的企業級別分佈式應用的構造。 





一個事務是有下列屬性的一個工作單元: 








原子性(ATOMICITY): 


一個事務要被完全的無二義性的做完或撤消。在任何操作出現一個錯誤的情況下,構成事務的所有操作的效果必須被撤消,數據應被回滾到以前的狀態。 





一致性(CONSISTENCY): 


一個事務應該保護所有定義在數據上的不變的屬性(例如完整性約束)。在完成了一個成功的事務時,數據應處於一致的狀態。換句話說,一個事務應該把系統從一個一致-狀態轉換到另一個一致狀態。舉個例子,在關係數據庫的情況下, 


一個一致的事務將保護定義在數據上的所有完整性約束。 





隔離性(ISOLATION): 


在同一個環境中可能有多個事務併發執行,而每個事務都應表現爲獨立執行。串行的執行一系列事務的效果應該同於併發的執行它們。這要求兩件事: 





在一個事務執行過程中,數據的中間的(可能不一致)狀態不應該被暴露給所有的其他事務。 


兩個併發的事務應該不能操作同一項數據。數據庫管理系統通常使用鎖來實現這個特徵。 





持久性(DURABILITY): 


一個被完成的事務的效果應該是持久的。 


說的狹隘一點:就是你做你的事,我做我的事,但對事務的基本特徵卻沒什麼改變。比如說是一工具箱,我借鉗子,你也借鉗子,但我時間上比你早那麼一點點,我用完了再給你,給你的還是一鉗子,而不是鈑手,而且你用的時候,東西也沒壞。


公共的東西就是要保護好,大家都要用的。





 這裏我就說說要常用的spring的事務管理。


  spring 有聲明式,也有編碼式的。編碼的開發我是很少用



就說說聲明的吧



。


這個要用到一個概念叫AOP(Aspect Oriented Programming).說白了就是在你的程序外面包層東西,讓他符合這個事務的特性。


Spring也提供聲明式事務管理。這是通過AOP實現的。大多數Spring用戶選擇聲明式事務管理,這是最少影響應用代碼的選擇,因而這是和非侵入性的輕量級容器的觀念是一致的。

1)通常通過TransactionProxyFactoryBean設置Spring事務代理。需要一個目標對象包裝在事務代理中。這個目標對象一般是一個普通Javabean。當我們定義TransactionProxyFactoryBean時,必須提供一個相關的PlatformTransactionManager的引用和事務屬性。事務屬性含有事務定義。例如:

 

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

這玩藝就是相關的 PlatformTransactionManager的引用和事務屬性。

 

然後主體到了:

 

  1. <bean id="transactionService"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
  2. <property name="transactionManager"> 
  3. <ref   local="transactionManager"/> 
  4. </property> 
  5. <property  name="target"> 
  6. <ref  local="transactionServiceControl"/> 
  7. </property> 
  8. <property  name="transactionAttributes"> 
  9. <props> 
  10. <prop key=”insert*”>PROPAGATION_REQUIRED,-MyCheckedException</prop> 
  11. <prop key=”update*”>PROPAGATION_REQUIRED</prop> 
  12. <prop key=”*”>PROPAGATION_REQUIRED,readOnly</prop> 
  13. </props> 
  14. </property> 
  15. </bean>

 

事務代理會實現目標對象的接口:這裏是屬性名是target的引用。id是transactionServiceControl。(使用CGLIB也可以實現具體類的代理。只要設置proxyTargetClass屬性爲true即可。如果目標對象沒有實現任何接口,這將自動設置該屬性爲true。通常,我們希望面向接口編程。)使用proxyInterfaces屬性來限定事務代理來代理指定接口也是可以。也可以通過從org.springframework.aop.framework.ProxyConfig繼承或所有AOP代理工廠共享的屬性來定製TransactionProxyFactoryBean行爲。

然後,說說屬性名是transactionAttributes意義:
這裏的transactionAttributes屬性是定義在org.springframework.transaction.interceptor.NameMathTransactionAttributeSource中的屬性格式設置。這個包括通配符的方法名稱映射是很直觀的,如”insert*”。注意insert*的映射的值包括回滾規則。”-MyCheckException”指定如果方法拋出MyCheckException或它的子類,事務會自動回滾。可以用逗號分隔多個回滾規則。“-”前綴強制回滾,“+”前綴指定提交(這允許即使拋出unchecked異常時也可以提交事務)。“PROPAGATION_REQUIRED”指定事務傳播範圍。

TransactionProxyFactoryBean允許你通過“preInterceptors”和“postInterceptors”屬性設置前或後的攔截操作。可以設置任意數量的前和後通過,它們的類型可以是Advistor(切入點),MethodInterceptor或被當前Spring配置支持的通知類型。例如:ThrowAdvice,AfterReturningAdvice或BeforeAdvice。這些通知必須支持實例共享模式。如果你需要高級AOP特性操作事務,通過org.springframework.aop.framework.ProxyFactoryBean,而不是TransactionProxyFactory實用代理創建者。

-----------------------------------------------------------------------------------------

這個是簡單的,對每一個邏輯,也就是代碼中的action來進行處理。這樣做的話,可能最後變成配置地獄,此時可以考慮使用自動事務代理。





根據spring的BeanName來管理自動代理可以這樣做:


<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">





<beans>


	<bean id="dataSource"


		class="org.apache.commons.dbcp.BasicDataSource">


		<property name="driverClassName">


			<value>com.mysql.jdbc.Driver</value>


		</property>


		<property name="url">


			<value>jdbc:mysql://localhost:3306/myuser</value>


		</property>


		<property name="username">


			<value>lighter</value>


		</property>


		<property name="password">


			<value>12345</value>


		</property>


	</bean>


	<bean id="sessionFactory"


		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">


		<property name="dataSource" ref="dataSource" />


		<property name="hibernateProperties">


			<props>


				<prop key="hibernate.dialect">


					org.hibernate.dialect.MySQLDialect


				</prop>


				<prop key="hibernate.show_sql">true</prop>


			</props>


		</property>


		<property name="mappingResources">


			<list>


				<value>org/mmc/dao/domain/User.hbm.xml</value>


			</list>


		</property>


	</bean>


	<!-- 配置Hibernate的事務管理器 -->


	<bean id="transactionManager"


		class="org.springframework.orm.hibernate3.HibernateTransactionManager">


		<property name="sessionFactory" ref="sessionFactory" />


	</bean>





	<!-- 定義事務攔截器bean -->


	<bean id="transactionInterceptor"


		class="org.springframework.transaction.interceptor.TransactionInterceptor">


		<property name="transactionManager" ref="transactionManager" />


		<property name="transactionAttributes">


			<props>


				<prop key="insert*">PROPAGATION_REQUIRED</prop>


				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>


				<prop key="*">PROPAGATION_REQUIRED</prop>


			</props>


		</property>


	</bean>





	<!-- 定義BeanNameAutoProxyCreator-->


	<bean


		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">


		<property name="beanNames">


		<!-- 所有名字以DAO,Service結尾的bean,將由該"bean後處理器"爲其創建事務代理;實際上應該在業務層進行事務管理,這裏只是舉一個簡單例子 -->


			<value>*DAO,*Service</value>


		</property>


		<!--  下面定義BeanNameAutoProxyCreator所需的事務攔截器-->


		<property name="interceptorNames">


			<list>


				<!-- 可以增加其他的攔截器 -->


				<value>transactionInterceptor</value>


			</list>


		</property>


	</bean>





	<!-- 舉下面這一個例子:這時候,這一個bean已經有了事務管理,可以增加類似的bean -->


	<bean id="searchUserDAO" class="org.mmc.dao.impl.SearchUserDAO">


		<property name="sessionFactory" ref="sessionFactory" />


	</bean>


</beans>


-----------------------------------------------------


下面再看一種也是常用的使用bean繼承簡化事務代理配置


	<bean id="test1" class="test.TransactionTestImpl">


		<property name="ds"><ref local="dataSource"/></property>


	</bean>





	<bean id="test2" class="test.TestImpl">


		<property name="ds"><ref local="dataSource"/></property>


	</bean>





    <bean id="baseTxProxy" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> 


        <property name="transactionManager"><ref bean="transactionManager"/></property> 


        <property name="transactionAttributes"> 


            <props> 


                <prop key="*">PROPAGATION_REQUIRED</prop> 


            </props> 


        </property> 


    </bean> 





    <bean id="testTrans1" parent="baseTxProxy"> 


        <property name="target"> 


            <ref local="test1"/> 


        </property> 


    </bean> 


    <bean id="testTrans2" parent="baseTxProxy"> 


        <property name="target"> 


            <ref local="test2"/> 


        </property> 


    </bean> 








使用繼承的方法,其配置文件是增量式的,不如採用上面所說的第一種方法簡捷,精煉。


ok 就這麼多,不知道說明白沒有。呵呵
http://www.douban.com/note/433877038/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章