通常通過TransactionProxyFactoryBean設置Spring事務代理。我們需要一個目標對象包裝在事務代理中。這個目標對象一般是一個普通Java對象的bean。當我們定義TransactionProxyFactoryBean時,必須提供一個相關的 PlatformTransactionManager的引用和
事務屬性。
事務屬性含有上面描述的事務定義。
<bean id="petStore"
????class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
????<property name="transactionManager"><ref bean="transactionManager"/></property>
????<property name="target"><ref bean="petStoreTarget"/></property>
????<property name="transactionAttributes">
????????<props>
????????????<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
????????????<prop key="update*">PROPAGATION_REQUIRED</prop>
????????????<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
????????</props>
????</property>
</bean>
事務代理會實現目標對象的接口:這里是id為petStoreTarget的bean。(使用 CGLIB也可以實現具體類的代理。只要設置proxyTargetClass屬性為true就可以。如果目標對象沒有實現任何接口,這將自動設置該屬性為true。通常,我們希望面向接口而不是類編程。)使用proxyInterfaces屬性來限定事務代理來代 理指定接口也是可以的
(一般來說是個好想法)。也可以通過從 org.springframework.aop.framework.ProxyConfig繼承或所有AOP代理工廠共享 的屬性來定制TransactionProxyFactoryBean的行為。
這里的transactionAttributes屬性定義在 org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource 中的屬性格式來設置。這個包括通配符的方法名稱映射是很直觀的。注意 insert*的映射的值包括回滾規則。添加的-MyCheckedException 指定如果方法拋出MyCheckedException或它的子類,事務將 會自動回滾??梢杂枚禾柗指舳x多個回滾規則。-前綴強制回滾,+前綴指定提交(這允許即使拋出unchecked異常時也可以提交事務,當然你自己要明白自己 在做什么)。
TransactionProxyFactoryBean允許你通過 “preInterceptors”和“postInterceptors”屬性設置“前”或“后”通知來提供額外的 攔截行為。可以設置任意數量的“前”和“后”通知,它們的類型可以是 Advisor(可以包含一個切入點), MethodInterceptor或被當前Spring配置支持的通知類型 (例如ThrowAdvice, AfterReturningtAdvice或BeforeAdvice, 這些都是默認支持的)。這些通知必須支持實例共享模式。如果你需要高級AOP特 性來使用事務,如有狀態的maxin,那最好使用通用的 org.springframework.aop.framework.ProxyFactoryBean, 而不是TransactionProxyFactoryBean實用代理創建者。
也可以設置自動代理:配置AOP框架,不需要單獨的代理定義類就可以生成類的 代理。
附兩個spring的事務配置例子:
<prop key="add">
???? PROPAGATION_REQUIRES_NEW, -MyException
</prop>
注:上面的意思是add方法將獨占一個事務,當事務處理過程中產生MyException異常或者該異常的子類將回滾該事務。
<prop key="loadAll">
????PROPAGATION_SUPPORTS, ISOLATION_READ_COMMITED, Readonly
</prop>
注:表示loadAll方法支持事務,而且不會讀取沒有提交事務的數據。它的數據為只讀(這樣有助于提高讀取的性能)
附A Spring中的所有事務策略
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED_NEW
PROPAGATION_SUPPORTS
附B Spring中所有的隔離策略:
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITED
ISOLATION_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
Spring事務類型祥解
大家可能在spring中經常看到這樣的定義:
?
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop>
估計有好多朋友還沒有弄清楚里面的值的意思,仔細看完下面應該知道自己什么情況下面應該使用什么樣的聲明。^_^
?
Spring中常用事務類型:
- PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
- PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。
- PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
- PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
- PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
- PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。
- PROPAGATION_NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。





























摘要:
Spring和EJB一樣,提供了兩種事務管理方式:編程式和聲明式。在考試系統中我們將使用聲明式的事務管理,這是spring推薦的做法。使用這種方式可以體驗到spring的強大便捷,而且我們無須在Dao類中編寫任何特殊的代碼,只需要通過配置文件就可以讓普通的java類加載到事務管理中,這個意義是很重大的。
本文Matrix永久鏡像:
http://www.matrix.org.cn/resource/article/1/1339.html說明:本文可能由Matrix原創,也可能由Matrix的會員整理,或者由
Matrix的Crawler在全球知名Java或者其他技術相關站點抓取并永久
保留鏡像,Matrix會保留所有原來的出處URL,并在顯著地方作出說明,
如果你發覺出處URL有誤,請聯系Matrix改正.
四、Spring中的事務控制
Spring和EJB一樣,提供了兩種事務管理方式:編程式和聲明式。在考試系統中我們將使用聲明式的事務管理,這是spring推薦的做法。使用這種方式可以體驗到spring的強大便捷,而且我們無須在Dao類中編寫任何特殊的代碼,只需要通過配置文件就可以讓普通的java類加載到事務管理中,這個意義是很重大的。
Spring中進行事務管理的通常方式是利用AOP(面向切片編程)的方式,為普通java類封裝事務控制,它是通過動態代理實現的,由于接口是延遲實例化的,spring在這段時間內通過攔截器,加載事務切片。原理就是這樣,具體細節請參考jdk中有關動態代理的文檔。本文主要講解如何在spring中進行事務控制。
動態代理的一個重要特征是,它是針對接口的,所以我們的dao要通過動態代理來讓spring接管事務,就必須在dao前面抽象出一個接口,當然如果沒有這樣的接口,那么spring會使用CGLIB來解決問題,但這不是spring推薦的方式,我們也不做討論。
參照前面的例子,我們為StudentManager.java定義一個接口,它的內容如下:
/*
* 創建日期 2005-3-25
*/
package org.bromon.spring.examer.student;
import java.util.List;
import org.bromon.spring.examer.pojo.Student;
/**
* @author Bromon
*/
public interface StudentManagerInterface
{
? ? public void add(Student s);
? ? public void del(Student s);
? ? public void update(Student s);
? ?
? ? public List loadAll();
? ? public Student loadById(int id);
}
StudentManager也應該做出修改,實現該接口:
public class StudentManager extends HibernateDaoSupport implements StudentManagerInterface
現在需要修改配置文件,用于定義Hibrenate適用的事務管理器,并且把sessionFactory注入進去,同時還需要通過注冊一個DefaultTransactionAttribute對象,來指出事務策略。其中sessionFactory的定義已經在本文的第三章中說明。
首先定義一個Hibernate的事務管理器,讓它來管理sessionFactory:
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
? ?? ?<property name="sessionFactory">
? ?? ?? ?<ref bean="sessionFactory"/>
? ?? ?</property>
</bean>
下面定義事務管理策略,我們希望把策略定義在方法這個級別上,提供最大的靈活性,本例中將add方法定義為:PROPAGATION_REQUIRES_NEW,這可以保證它將始終運行在一個事務中。
<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
? ?? ?<property name="properties">
? ?? ?? ?<props>
? ?? ?? ?? ?<prop key="add">
? ?? ?? ?? ?? ?PROPAGATION_REQUIRES_NEW
? ?? ?? ?? ?</prop>
? ?? ?? ?</props>
? ?? ?</property>
? ?</bean>
我們不僅可以為add方法定義事務策略,還可以定義事務隔離程度和回滾策略,他們以逗號隔開,比如我們的add事務可以定義為:
<prop key="add">
? ?PROPAGATION_REQUIRES_NEW,-ExamerException
</prop
>
這個事務策略表示add方法將會獨占一個事務,當事務過程中產生ExamerException異常,事務會回滾。
Add/update/del都是寫入方法,對于select(讀?。┓椒?,我們可以指定較為復雜的事務策略,比如對于loadAll()方法:
<prop key=”loadAll”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>
該事務的含義為,loadAll方法支持事務,不會讀去位提交的數據,它的數據為只讀(可提高執行速度)。
如你所見,我們的StudentManagerInterface接口中還有一個loadById(int id)方法,也許我們將來還會有很多的loadByXXXX的方法,難道要意義為他們指定事務策略?太煩人了,他們應該和loadAll()一樣,所以我們可以使用通配符,定義所有的loadXXXX方法:
<prop key=”load*”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>
現在可以定義事務管理器:
<bean id="studentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
? ?? ?<property name="target">
? ?? ?? ?<ref bean="studentManager"/>
? ?? ?</property>
? ?? ?<property name="transactionManager">
? ?? ?? ?<ref bean="transactionManager"/>
? ?? ?</property>
? ?? ?<property name="transactionAttributeSource">
? ?? ?? ?<ref bean="transactionAttributeSource"/>
? ?? ?</property>
</bean>
這個bean的外觀是一個接口(StudentManagerInterface),我們指出了它的具體實現(studentManager),而且為它綁定了事務策略。在客戶端使用的時候,獲得對象是StudentManagerInterface,所有的操作都是針對這個接口的。測試代碼并沒有改變,我們雖然修改了很多地方,加入了事務控制,但是客戶端并沒有受到影響,這也體現了spring的一些優勢。測試代碼如下:
public void testAdd()
? ? {
? ? ? ? ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
? ? ? ? StudentManager sm=(StudentManager)ctx.getBean("studentManager");
? ? ? ?
? ? ? ? Student s=new Student();
? ? ? ? s.setId(1);
? ? ? ? s.setName("bromon");
? ? ? ? s.setPassword("123");
? ? ? ? s.setGrade(1);
? ? ? ? s.setSex(0);
? ? ? ?
? ? ? ? sm.add(s);
}
通過以上的代碼可以看出,spring可以簡單的把普通的java class納入事務管理,聲明性的事務操作起來也很容易。有了spring之后,聲明性事務不再是EJB獨有,我們不必為了獲得聲明性事務的功能而去忍受EJB帶來的種種不便。
我所使用的mysql是不支持事務的,你可以更換使用PostgreSQL,有了spring+hibernate,更換db并不像以前那樣恐怖了,步驟很簡單:
1、 添加PostgreSQL的jdbc驅動
2、 修改dataSource配置,包括驅動名稱、url、帳號、密碼
3、 修改sessionFactory的數據庫dailet為net.sf.hibernate.dialect.PostgreSQLDialect
4、 修改hbm.xml中的主鍵生成策略為increment
所有的修改都在配置文件中完成,業務代碼不需要任何修改,我很滿意,How about u?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
傳統的:
?1?<bean?id="dataSource"?class="org.apache.commons.dbcp.BasicDataSource"?destroy-method="close">
?2?????????<property?name="driverClassName"?value="oracle.jdbc.driver.OracleDriver"?/>
?3?????????<property?name="url"?value="jdbc:oracle:thin:@127.0.0.1:1521:dev"?/>
?4?????????<property?name="username"?value="kaktos"?/>
?5?????????<property?name="password"?value="kaktos"?/>
?6?????</bean>
?7?
?8?????<bean?id="txManager"
?9?????????class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
10?????????<property?name="dataSource"?ref="dataSource"?/>
11?????</bean>
12?
13?????<bean?id="businessBean"
14?????????class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
15?????????<property?name="transactionManager"?ref="txManager"?/>
16?????????<property?name="target"?ref="businessBeanTarget"?/>
17?????????<property?name="transactionAttributes">
18?????????????<props>????????????????
19?????????????????<prop?key="*">PROPAGATION_REQUIRED</prop>
20?????????????</props>
21?????????</property>
22?????</bean>
23?????
24?????<bean?id="businessBeanTarget"?class="sample.spring.trans.BusinessBean">
25?????????<property?name="dataSource"?ref="dataSource"?/>
26?????</bean>
這樣做的弊端就是不得不為每個需要事務的bean做一次聲明,如果所有的bean都基本上有一致的配置,這樣就太繁瑣啦。
下面是第二種方式:
?1?<beans>
?2?????<bean?id="dataSource"?class="org.apache.commons.dbcp.BasicDataSource"?destroy-method="close">
?3?????????<property?name="driverClassName"?value="oracle.jdbc.driver.OracleDriver"?/>
?4?????????<property?name="url"?value="jdbc:oracle:thin:@127.0.0.1:1521:dev"?/>
?5?????????<property?name="username"?value="kaktos"?/>
?6?????????<property?name="password"?value="kaktos"?/>
?7?????</bean>
?8?
?9?????<bean?id="txManager"
10?????????class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
11?????????<property?name="dataSource"?ref="dataSource"?/>
12?????</bean>
13?
14?????<bean?id="matchAllWithPropReq"
15?????????class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
16?????????<property?name="transactionAttribute"?value="PROPAGATION_REQUIRED"?/>
17?????</bean>
18?????
19?????<bean?id="matchAllTxInterceptor"?class="org.springframework.transaction.interceptor.TransactionInterceptor">
20?????????<property?name="transactionManager"?ref="txManager"?/>
21?????????<property?name="transactionAttributeSource"?ref="matchAllWithPropReq"?/>
22?????</bean>
23?
24?????<bean?id="autoProxyCreator"
25?????????class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
26?????????<property?name="interceptorNames">
27?????????????<list>
28?????????????????<idref?local="matchAllTxInterceptor"?/>
29?????????????</list>
30?????????</property>
31?????????<property?name="beanNames">
32?????????????<list>
33?????????????????<idref?local="businessBean"?/>
34?????????????</list>
35?????????</property>
36?????</bean>
37?????
38?????<!--??my?beans??-->
39?????<bean?id="businessBean"?class="sample.spring.trans.BusinessBean">
40?????????<property?name="dataSource"?ref="dataSource"?/>
41?????</bean>
42?</beans>
BeanNameAutoProxyCreator會在applicationcontext初始化后自動為beanNames屬性中的bean建立proxy。