一、事務的隔離級别使用Spring 聲明式事務時,有一個非常重要的概念就是事務屬性。事務屬性通常由事務的傳播行為,事務的隔離級别,事務的逾時值和事務隻讀标志組成。
org.springframework.transaction包裡面的TransactionDefinition類
getTimeout()方法,它傳回事務必須在多少秒内完成。
isReadOnly(),事務是否隻讀,事務管理器能夠根據這個傳回值進行優化,確定事務是隻讀的。
getIsolationLevel()方法傳回事務的隔離級别,事務管理器根據它來控制另外一個事務可以看到本事務内的哪些資料。
在TransactionDefinition接口中定義了四個不同的事務隔離級别:
1) ISOLATION_DEFAULT 這是一個 PlatfromTransactionManager預設的隔離級别,使用資料庫預設的事務隔離級别(讀未送出).另外四個與JDBC的隔離級别相對應
2) ISOLATION_READ_UNCOMMITTED這是事務最低的隔離級别,它充許别外一個事務可以看到這個事務未送出的資料。這種隔離級别會産生髒讀,不可重複讀和幻像讀。
3) ISOLATION_READ_COMMITTED 保證一個事務修改的資料送出後才能被另外一個事務讀取。另外一個事務不能讀取該事務未送出的資料。這種事務隔離級别可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀。
4) ISOLATION_REPEATABLE_READ 這種事務隔離級别可以防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未送出的資料外,還保證了避免下面的情況産生(不可重複讀)
二、事務的傳播性質
定義了關于用戶端和被調用方法的事務邊界。傳播規則就是在說明新的事務是否要被啟動或是挂起,或者方法是否要在事務環境中運作。在TransactionDefinition接口中定義了七個事務傳播行為:
1) PROPAGATION_REQUIRED 如果存在一個事務,則支援目前事務。如果沒有事務則開啟一個新的事務;
2) PROPAGATION_SUPPORTS 如果存在一個事務,支援目前事務。如果沒有事務,則非事務的執行;
3) PROPAGATION_MANDATORY 如果已經存在一個事務,支援目前事務。如果沒有一個活動的事務,則抛出異;
4)PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務。如果一個事務已經存在,則将這個存在的事務挂起;
5) PROPAGATION_NOT_SUPPORTED總是非事務地執行,并挂起任何存在的事務;
6) PROPAGATION_NEVER總是非事務地執行,如果存在一個活動事務,則抛出異常;
7) PROPAGATION_NESTED如果一個活動的事務存在,則運作在一個嵌套的事務中. 如果沒有活動事務, 則按 TransactionDefinition.PROPAGATION_REQUIRED 屬性執行;
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 事務攔截器,激活事務管理器所必須的bean -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<!-- 配置事務屬性 -->
<property name="transactionAttributes">
<props>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<!--BeanNameAutoProxyCreator是個根據bean名生成自動代理的代理建立器,該bean通常需要接受兩個參數。一個是指定需要代理的bean,另一個是代理bean所需的事務攔截器 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 可以是Service或DAO層(最好是針對業務層*Service) -->
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
在Spring中聲明式的事務管理是用Spring的AOP來實作的。了解了這些後我們要考慮的是我們的事務到底要加在那一層,
在我們的項目中往往将事務加到serivce層,這樣做的好是:比如在DAO層我有三個方法來對資料進行操作,而我們的一次業務邏輯,
需要我們要調用這三個方法才能完成這個一業務而這三方法還要放到一個事務中去,
我們要是将事務配在DAO層我們做法隻有将這三個方法分别加上一個事務,這顯然違背了我們的業務需求。
而在我們的service層中可以用一個方法來調用Dao層中的這三個方法,這樣我們隻要将serive層中的這個方法加上一個事務控制,
我們業務需求就很容易的解決了。是以我們将事務大多數的要加在service層上。
<!-- 以AspectJ方式 定義 AOP -->
<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(* com.*.service.impl.*Manager*.*(..))" advice-ref="txAdvice" />
</aop:config>
<!-- 基本事務定義,使用transactionManager作事務管理,預設get*方法的事務為readonly,其餘方法按預設設定. -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception">
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception">
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception">
</tx:attributes>
</tx:advice>