通常通過(guò)TransactionProxyFactoryBean設(shè)置Spring事務(wù)代理。我們需要一個(gè)目標(biāo)對(duì)象包裝在事務(wù)代理中。這個(gè)目標(biāo)對(duì)象一般是一個(gè)普通Java對(duì)象的bean。當(dāng)我們定義TransactionProxyFactoryBean時(shí),必須提供一個(gè)相關(guān)的 PlatformTransactionManager的引用和事務(wù)屬性事務(wù)屬性含有上面描述的事務(wù)定義。
<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>

事務(wù)代理會(huì)實(shí)現(xiàn)目標(biāo)對(duì)象的接口:這里是id為petStoreTarget的bean。(使用 CGLIB也可以實(shí)現(xiàn)具體類的代理。只要設(shè)置proxyTargetClass屬性為true就可以。如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)任何接口,這將自動(dòng)設(shè)置該屬性為true。通常,我們希望面向接口而不是類編程。)使用proxyInterfaces屬性來(lái)限定事務(wù)代理來(lái)代 理指定接口也是可以的(一般來(lái)說(shuō)是個(gè)好想法)。也可以通過(guò)從 org.springframework.aop.framework.ProxyConfig繼承或所有AOP代理工廠共享 的屬性來(lái)定制TransactionProxyFactoryBean的行為。

這里的transactionAttributes屬性定義在 org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource 中的屬性格式來(lái)設(shè)置。這個(gè)包括通配符的方法名稱映射是很直觀的。注意 insert*的映射的值包括回滾規(guī)則。添加的-MyCheckedException 指定如果方法拋出MyCheckedException或它的子類,事務(wù)將 會(huì)自動(dòng)回滾。可以用逗號(hào)分隔定義多個(gè)回滾規(guī)則。-前綴強(qiáng)制回滾,+前綴指定提交(這允許即使拋出unchecked異常時(shí)也可以提交事務(wù),當(dāng)然你自己要明白自己 在做什么)。

TransactionProxyFactoryBean允許你通過(guò) “preInterceptors”和“postInterceptors”屬性設(shè)置“前”或“后”通知來(lái)提供額外的 攔截行為。可以設(shè)置任意數(shù)量的“前”和“后”通知,它們的類型可以是 Advisor(可以包含一個(gè)切入點(diǎn)), MethodInterceptor或被當(dāng)前Spring配置支持的通知類型 (例如ThrowAdviceAfterReturningtAdviceBeforeAdvice, 這些都是默認(rèn)支持的)。這些通知必須支持實(shí)例共享模式。如果你需要高級(jí)AOP特 性來(lái)使用事務(wù),如有狀態(tài)的maxin,那最好使用通用的 org.springframework.aop.framework.ProxyFactoryBean, 而不是TransactionProxyFactoryBean實(shí)用代理創(chuàng)建者。

也可以設(shè)置自動(dòng)代理:配置AOP框架,不需要單獨(dú)的代理定義類就可以生成類的 代理。

附兩個(gè)spring的事務(wù)配置例子:
<prop key="add">
???? PROPAGATION_REQUIRES_NEW, -MyException
</prop>
注:上面的意思是add方法將獨(dú)占一個(gè)事務(wù),當(dāng)事務(wù)處理過(guò)程中產(chǎn)生MyException異常或者該異常的子類將回滾該事務(wù)。

<prop key="loadAll">
????PROPAGATION_SUPPORTS, ISOLATION_READ_COMMITED, Readonly
</prop>
注:表示loadAll方法支持事務(wù),而且不會(huì)讀取沒(méi)有提交事務(wù)的數(shù)據(jù)。它的數(shù)據(jù)為只讀(這樣有助于提高讀取的性能)

附A Spring中的所有事務(wù)策略

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事務(wù)類型祥解

大家可能在spring中經(jīng)常看到這樣的定義:

?

<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop>

估計(jì)有好多朋友還沒(méi)有弄清楚里面的值的意思,仔細(xì)看完下面應(yīng)該知道自己什么情況下面應(yīng)該使用什么樣的聲明。^_^

?

Spring中常用事務(wù)類型:

  • PROPAGATION_REQUIRED--支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù)。這是最常見(jiàn)的選擇。
  • PROPAGATION_SUPPORTS--支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行。
  • PROPAGATION_MANDATORY--支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就拋出異常。
  • PROPAGATION_REQUIRES_NEW--新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NOT_SUPPORTED--以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NEVER--以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
  • PROPAGATION_NESTED--如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒(méi)有事務(wù),則進(jìn)行與PROPAGATION_REQUIRED類似的操作。
摘要:
Spring和EJB一樣,提供了兩種事務(wù)管理方式:編程式和聲明式。在考試系統(tǒng)中我們將使用聲明式的事務(wù)管理,這是spring推薦的做法。使用這種方式可以體驗(yàn)到spring的強(qiáng)大便捷,而且我們無(wú)須在Dao類中編寫(xiě)任何特殊的代碼,只需要通過(guò)配置文件就可以讓普通的java類加載到事務(wù)管理中,這個(gè)意義是很重大的。


本文Matrix永久鏡像:http://www.matrix.org.cn/resource/article/1/1339.html
說(shuō)明:本文可能由Matrix原創(chuàng),也可能由Matrix的會(huì)員整理,或者由
Matrix的Crawler在全球知名Java或者其他技術(shù)相關(guān)站點(diǎn)抓取并永久
保留鏡像,Matrix會(huì)保留所有原來(lái)的出處URL,并在顯著地方作出說(shuō)明,
如果你發(fā)覺(jué)出處URL有誤,請(qǐng)聯(lián)系Matrix改正.
四、Spring中的事務(wù)控制

Spring和EJB一樣,提供了兩種事務(wù)管理方式:編程式和聲明式。在考試系統(tǒng)中我們將使用聲明式的事務(wù)管理,這是spring推薦的做法。使用這種方式可以體驗(yàn)到spring的強(qiáng)大便捷,而且我們無(wú)須在Dao類中編寫(xiě)任何特殊的代碼,只需要通過(guò)配置文件就可以讓普通的java類加載到事務(wù)管理中,這個(gè)意義是很重大的。

Spring中進(jìn)行事務(wù)管理的通常方式是利用AOP(面向切片編程)的方式,為普通java類封裝事務(wù)控制,它是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,由于接口是延遲實(shí)例化的,spring在這段時(shí)間內(nèi)通過(guò)攔截器,加載事務(wù)切片。原理就是這樣,具體細(xì)節(jié)請(qǐng)參考jdk中有關(guān)動(dòng)態(tài)代理的文檔。本文主要講解如何在spring中進(jìn)行事務(wù)控制。

動(dòng)態(tài)代理的一個(gè)重要特征是,它是針對(duì)接口的,所以我們的dao要通過(guò)動(dòng)態(tài)代理來(lái)讓spring接管事務(wù),就必須在dao前面抽象出一個(gè)接口,當(dāng)然如果沒(méi)有這樣的接口,那么spring會(huì)使用CGLIB來(lái)解決問(wèn)題,但這不是spring推薦的方式,我們也不做討論。

參照前面的例子,我們?yōu)镾tudentManager.java定義一個(gè)接口,它的內(nèi)容如下:

/*
* 創(chuàng)建日期 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也應(yīng)該做出修改,實(shí)現(xiàn)該接口:

public class StudentManager extends HibernateDaoSupport implements StudentManagerInterface

現(xiàn)在需要修改配置文件,用于定義Hibrenate適用的事務(wù)管理器,并且把sessionFactory注入進(jìn)去,同時(shí)還需要通過(guò)注冊(cè)一個(gè)DefaultTransactionAttribute對(duì)象,來(lái)指出事務(wù)策略。其中sessionFactory的定義已經(jīng)在本文的第三章中說(shuō)明。

首先定義一個(gè)Hibernate的事務(wù)管理器,讓它來(lái)管理sessionFactory:
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
? ?? ?<property name="sessionFactory">
? ?? ?? ?<ref bean="sessionFactory"/>
? ?? ?</property>
</bean>

下面定義事務(wù)管理策略,我們希望把策略定義在方法這個(gè)級(jí)別上,提供最大的靈活性,本例中將add方法定義為:PROPAGATION_REQUIRES_NEW,這可以保證它將始終運(yùn)行在一個(gè)事務(wù)中。

<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
? ?? ?<property name="properties">
? ?? ?? ?<props>
? ?? ?? ?? ?<prop key="add">
? ?? ?? ?? ?? ?PROPAGATION_REQUIRES_NEW
? ?? ?? ?? ?</prop>
? ?? ?? ?</props>
? ?? ?</property>
? ?</bean>

我們不僅可以為add方法定義事務(wù)策略,還可以定義事務(wù)隔離程度和回滾策略,他們以逗號(hào)隔開(kāi),比如我們的add事務(wù)可以定義為:

<prop key="add">
? ?PROPAGATION_REQUIRES_NEW,-ExamerException
</prop
>

這個(gè)事務(wù)策略表示add方法將會(huì)獨(dú)占一個(gè)事務(wù),當(dāng)事務(wù)過(guò)程中產(chǎn)生ExamerException異常,事務(wù)會(huì)回滾。

Add/update/del都是寫(xiě)入方法,對(duì)于select(讀取)方法,我們可以指定較為復(fù)雜的事務(wù)策略,比如對(duì)于loadAll()方法:

<prop key=”loadAll”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>


該事務(wù)的含義為,loadAll方法支持事務(wù),不會(huì)讀去位提交的數(shù)據(jù),它的數(shù)據(jù)為只讀(可提高執(zhí)行速度)。

如你所見(jiàn),我們的StudentManagerInterface接口中還有一個(gè)loadById(int id)方法,也許我們將來(lái)還會(huì)有很多的loadByXXXX的方法,難道要意義為他們指定事務(wù)策略?太煩人了,他們應(yīng)該和loadAll()一樣,所以我們可以使用通配符,定義所有的loadXXXX方法:

<prop key=”load*”>
? ?? ?PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITED,readOnly
? ?</prop>


現(xiàn)在可以定義事務(wù)管理器:
<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>


這個(gè)bean的外觀是一個(gè)接口(StudentManagerInterface),我們指出了它的具體實(shí)現(xiàn)(studentManager),而且為它綁定了事務(wù)策略。在客戶端使用的時(shí)候,獲得對(duì)象是StudentManagerInterface,所有的操作都是針對(duì)這個(gè)接口的。測(cè)試代碼并沒(méi)有改變,我們雖然修改了很多地方,加入了事務(wù)控制,但是客戶端并沒(méi)有受到影響,這也體現(xiàn)了spring的一些優(yōu)勢(shì)。測(cè)試代碼如下:

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);
}


通過(guò)以上的代碼可以看出,spring可以簡(jiǎn)單的把普通的java class納入事務(wù)管理,聲明性的事務(wù)操作起來(lái)也很容易。有了spring之后,聲明性事務(wù)不再是EJB獨(dú)有,我們不必為了獲得聲明性事務(wù)的功能而去忍受EJB帶來(lái)的種種不便。

我所使用的mysql是不支持事務(wù)的,你可以更換使用PostgreSQL,有了spring+hibernate,更換db并不像以前那樣恐怖了,步驟很簡(jiǎn)單:

1、 添加PostgreSQL的jdbc驅(qū)動(dòng)
2、 修改dataSource配置,包括驅(qū)動(dòng)名稱、url、帳號(hào)、密碼
3、 修改sessionFactory的數(shù)據(jù)庫(kù)dailet為net.sf.hibernate.dialect.PostgreSQLDialect
4、 修改hbm.xml中的主鍵生成策略為increment

所有的修改都在配置文件中完成,業(yè)務(wù)代碼不需要任何修改,我很滿意,How about u?

?

??????????????????????????

spring聲明式事務(wù)管理的兩種方式

傳統(tǒng)的:
?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>

這樣做的弊端就是不得不為每個(gè)需要事務(wù)的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會(huì)在applicationcontext初始化后自動(dòng)為beanNames屬性中的bean建立proxy。