Spring事務處理案例總結 rollback-for使用
阿新 • • 發佈:2019-02-15
spring只是控制資料庫的事務提交和回滾,藉助於java的反射機制,在事務控制的方法(通常是service層的方法)前後獲取事務開啟session,然後執行你的資料操作,如果你的方法內有異常被丟擲,spring會捕獲異常並回滾你在這個方法內所有的資料操作,如果成功則提交所有的資料,最後spring會幫你關閉需要關閉的東西。所以spring想要做的是,要程式設計師專注於寫邏輯,不需要關係資料庫何時開啟和關閉連線。
關於事務的傳播屬性有下面幾種配置:
REQUIRED:業務方法需要在一個事務中執行,如果方法執行時,已經處於一個事務中,那麼加入到該事務中,否則自己建立一個新的事務.(Spring預設的事務傳播屬性)
NOT_SUPPORTED:宣告方法不需要事務,如果方法沒有關聯到一個事務,容器不會為它開啟事務,如果方法在一個事務中被呼叫,該事務被掛起,在方法呼叫結束後,原先的事務便會恢復執行
REQUIRESNEW:不管是否存在事務,業務方法總會為自己發起一個新的事務,如果方法執行時已經存在一個事務,則該事務會被掛起,新的事務被建立,知道方法執行結束,新事務才結束,原先的事務才恢復執行。
MANDATORY:指定業務方法只能在一個已經存在的事務中執行,業務方法不能自己發起事務,如果業務方法沒有在事務的環境下呼叫,則容器會丟擲異常
SUPPORTS:如果業務方法在事務中被呼叫,則成為事務中的一部分,如果沒有在事務中呼叫,則在沒有事務的環境下執行。
NEVER:指定業務方法絕對不能在事務範圍內執行,否則會丟擲異常。
NESTED:如果業務方法執行時已經存在一個事務,則新建一個巢狀的事務,該事務可以有多個回滾點,如果沒有事務,則按REQUIRED屬性執行. 注意:業務方法內部事務的回滾不會對外部事務造成影響,但是外部事務的回滾會影響內部事務。
Spring配置檔案中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,無論哪種配置方式,一般變化的只是代理機制這部分。
DataSource、TransactionManager這兩部分只是會根據資料訪問方式有所變化,比如使用Hibernate進行資料訪問時,DataSource實際為SessionFactory,TransactionManager的實現為HibernateTransactionManager。
注:這是作為公共使用的事務管理器Bean。這個會是事先配置好的,不需各個模組各自去配。
下面就開始配置各個模組所必須的部分,在各自的applicationContext-XXX-beans.xml配置的對於事務管理的詳細資訊。
首先就是配置事務的傳播特性,如下:
rollback-for 在該方法中有異常則進行回滾
需要注意的地方:
(1) advice(建議)的命名:由於每個模組都會有自己的Advice,所以在命名上需要作出規範,初步的構想就是模組名+Advice(只是一種命名規範)。
(2) tx:attribute標籤所配置的是作為事務的方法的命名型別。
如<tx:method name="save*" propagation="REQUIRED"/>
其中*為萬用字元,即代表以save為開頭的所有方法,即表示符合此命名規則的方法作為一個事務。
propagation="REQUIRED"代表支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
(3) aop:pointcut標籤配置參與事務的類,由於是在Service中進行資料庫業務操作,配的應該是包含那些作為事務的方法的Service類。
首先應該特別注意的是id的命名,同樣由於每個模組都有自己事務切面,所以我覺得初步的命名規則因為 all+模組名+ServiceMethod。而且每個模組之間不同之處還在於以下一句:
expression="execution(* com.test.testAda.test.model.service.*.*(..))"
其中第一個*代表返回值,第二*代表service下子包,第三個*代表方法名,“(..)”代表方法引數。
(4) aop:advisor標籤就是把上面我們所配置的事務管理兩部分屬性整合起來作為整個事務管理。
圖解:
使用事務有5種:
第一種方式:每個Bean都有一個代理
第二種方式:所有Bean共享一個代理基類
第三種方式:使用攔截器
第四種方式:使用tx標籤配置的攔截器
第五種方式:全註解(用註釋的形式)
此時在DAO上需加上@Transactional註解,如下:
關於事務的傳播屬性有下面幾種配置:
REQUIRED:業務方法需要在一個事務中執行,如果方法執行時,已經處於一個事務中,那麼加入到該事務中,否則自己建立一個新的事務.(Spring預設的事務傳播屬性)
NOT_SUPPORTED:宣告方法不需要事務,如果方法沒有關聯到一個事務,容器不會為它開啟事務,如果方法在一個事務中被呼叫,該事務被掛起,在方法呼叫結束後,原先的事務便會恢復執行
REQUIRESNEW:不管是否存在事務,業務方法總會為自己發起一個新的事務,如果方法執行時已經存在一個事務,則該事務會被掛起,新的事務被建立,知道方法執行結束,新事務才結束,原先的事務才恢復執行。
MANDATORY:指定業務方法只能在一個已經存在的事務中執行,業務方法不能自己發起事務,如果業務方法沒有在事務的環境下呼叫,則容器會丟擲異常
SUPPORTS:如果業務方法在事務中被呼叫,則成為事務中的一部分,如果沒有在事務中呼叫,則在沒有事務的環境下執行。
NEVER:指定業務方法絕對不能在事務範圍內執行,否則會丟擲異常。
NESTED:如果業務方法執行時已經存在一個事務,則新建一個巢狀的事務,該事務可以有多個回滾點,如果沒有事務,則按REQUIRED屬性執行. 注意:業務方法內部事務的回滾不會對外部事務造成影響,但是外部事務的回滾會影響內部事務。
Spring配置檔案中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,無論哪種配置方式,一般變化的只是代理機制這部分。
DataSource、TransactionManager這兩部分只是會根據資料訪問方式有所變化,比如使用Hibernate進行資料訪問時,DataSource實際為SessionFactory,TransactionManager的實現為HibernateTransactionManager。
<!-- 配置事務管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean>
注:這是作為公共使用的事務管理器Bean。這個會是事先配置好的,不需各個模組各自去配。
下面就開始配置各個模組所必須的部分,在各自的applicationContext-XXX-beans.xml配置的對於事務管理的詳細資訊。
首先就是配置事務的傳播特性,如下:
rollback-for 在該方法中有異常則進行回滾
<!-- 配置事務傳播特性 --> <tx:advice id="TestAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="del*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="find*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="get*" propagation="REQUIRED" rollback-for="Throwable"/> <tx:method name="apply*" propagation="REQUIRED" rollback-for="Throwable"/> </tx:attributes> </tx:advice> <!-- 配置參與事務的類 --> <aop:config> <aop:pointcut id="allTestServiceMethod" expression="execution(* com.test.testAda.test.model.service.*.*(..))"/> <aop:advisor pointcut-ref="allTestServiceMethod" advice-ref="TestAdvice" /> </aop:config>
需要注意的地方:
(1) advice(建議)的命名:由於每個模組都會有自己的Advice,所以在命名上需要作出規範,初步的構想就是模組名+Advice(只是一種命名規範)。
(2) tx:attribute標籤所配置的是作為事務的方法的命名型別。
如<tx:method name="save*" propagation="REQUIRED"/>
其中*為萬用字元,即代表以save為開頭的所有方法,即表示符合此命名規則的方法作為一個事務。
propagation="REQUIRED"代表支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
(3) aop:pointcut標籤配置參與事務的類,由於是在Service中進行資料庫業務操作,配的應該是包含那些作為事務的方法的Service類。
首先應該特別注意的是id的命名,同樣由於每個模組都有自己事務切面,所以我覺得初步的命名規則因為 all+模組名+ServiceMethod。而且每個模組之間不同之處還在於以下一句:
expression="execution(* com.test.testAda.test.model.service.*.*(..))"
其中第一個*代表返回值,第二*代表service下子包,第三個*代表方法名,“(..)”代表方法引數。
(4) aop:advisor標籤就是把上面我們所配置的事務管理兩部分屬性整合起來作為整個事務管理。
圖解:
使用事務有5種:
第一種方式:每個Bean都有一個代理
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定義事務管理器(宣告式的事務) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 配置DAO --> <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="userDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置事務管理器 --> <property name="transactionManager" ref="transactionManager" /> <property name="target" ref="userDaoTarget" /> <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" /> <!-- 配置事務屬性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
第二種方式:所有Bean共享一個代理基類
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定義事務管理器(宣告式的事務) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="transactionBase" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true"> <!-- 配置事務管理器 --> <property name="transactionManager" ref="transactionManager" /> <!-- 配置事務屬性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!-- 配置DAO --> <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="userDao" parent="transactionBase" > <property name="target" ref="userDaoTarget" /> </bean> </beans>
第三種方式:使用攔截器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定義事務管理器(宣告式的事務) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager" /> <!-- 配置事務屬性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>*Dao</value> </list> </property> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> </list> </property> </bean> <!-- 配置DAO --> <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
第四種方式:使用tx標籤配置的攔截器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:annotation-config /> <context:component-scan base-package="com.bluesky" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定義事務管理器(宣告式的事務) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="interceptorPointCuts" expression="execution(* com.bluesky.spring.dao.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" /> </aop:config> </beans>
第五種方式:全註解(用註釋的形式)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:annotation-config /> <context:component-scan base-package="com.bluesky" /> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> </bean> <!-- 定義事務管理器(宣告式的事務) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
此時在DAO上需加上@Transactional註解,如下:
package com.bluesky.spring.dao;
import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;
import com.bluesky.spring.domain.User;
@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
public List<User> listUsers() {
return this.getSession().createQuery("from User").list();
}
}