?
Dieses Dokument verwendet PHP-Handbuch für chinesische Websites Freigeben
Spring事務(wù)抽象的關(guān)鍵是事務(wù)策略的概念。這個(gè)概念由org.springframework.transaction.PlatformTransactionManager
接口定義如下:
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
這首先是一個(gè)SPI接口,雖然它也可以在 編程 中使用。注意按照Spring框架的哲學(xué),PlatformTransactionManager
是一個(gè) 接口。因而如果需要它可以很容易地被模擬和樁化。它也沒(méi)有和一個(gè)查找策略如JNDI捆綁在一起:PlatformTransactionManager
的實(shí)現(xiàn)定義和其他Spring IoC容器中的對(duì)象一樣。這個(gè)好處使得即使使用JTA,也是一個(gè)很有價(jià)值的抽象:事務(wù)代碼可以比直接使用JTA更加容易測(cè)試。
繼續(xù)Spring哲學(xué),可由任何 PlatformTransactionManager
的接口方法拋出的 TransactionException
是unchecked exception(繼承自java.lang.RuntimeException
)的。底層的事務(wù)失敗幾乎總是致命的。很少情況下應(yīng)用程序代碼可以從它們中恢復(fù),不過(guò)應(yīng)用開(kāi)發(fā)者依然可以捕獲并處理TransactionException
,他們可以自由決定怎么干。
getTransaction(..)
方法根據(jù)一個(gè)類(lèi)型為 TransactionDefinition
的參數(shù)返回一個(gè) TransactionStatus
對(duì)象。返回的 TransactionStatus
對(duì)象可能代表一個(gè)新的或已經(jīng)存在的事務(wù)(如果在當(dāng)前調(diào)用堆棧有一個(gè)符合條件的事務(wù)。如同J2EE事務(wù)環(huán)境,一個(gè) TransactionStatus
也是和執(zhí)行 線(xiàn)程 綁定的)。
TransactionDefinition
接口指定:
事務(wù)隔離:當(dāng)前事務(wù)和其它事務(wù)的隔離的程度。例如,這個(gè)事務(wù)能否看到其他事務(wù)未提交的寫(xiě)數(shù)據(jù)?
事務(wù)傳播:通常在一個(gè)事務(wù)中執(zhí)行的所有代碼都會(huì)在這個(gè)事務(wù)中運(yùn)行。但是,如果一個(gè)事務(wù)上下文已經(jīng)存在,有幾個(gè)選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為:例如,簡(jiǎn)單地在現(xiàn)有的事務(wù)中繼續(xù)運(yùn)行(大多數(shù)情況);或者掛起現(xiàn)有事務(wù),創(chuàng)建一個(gè)新的事務(wù)。Spring提供EJB CMT中常見(jiàn)的事務(wù)傳播選項(xiàng)。
事務(wù)超時(shí): 事務(wù)在超時(shí)前能運(yùn)行多久(自動(dòng)被底層的事務(wù)基礎(chǔ)設(shè)施回滾)。
只讀狀態(tài): 只讀事務(wù)不修改任何數(shù)據(jù)。只讀事務(wù)在某些情況下(例如當(dāng)使用Hibernate時(shí)),是一種非常有用的優(yōu)化。
這些設(shè)置反映了標(biāo)準(zhǔn)概念。如果需要,請(qǐng)查閱討論事務(wù)隔離層次和其他核心事務(wù)概念的資源:理解這些概念在使用Spring框架和其他事務(wù)管理解決方案時(shí)是非常關(guān)鍵的。
TransactionStatus
接口為處理事務(wù)的代碼提供一個(gè)簡(jiǎn)單的控制事務(wù)執(zhí)行和查詢(xún)事務(wù)狀態(tài)的方法。這個(gè)概念應(yīng)該是熟悉的,因?yàn)樗鼈冊(cè)谒械氖聞?wù)API中是相同的:
public interface TransactionStatus { boolean isNewTransaction(); void setRollbackOnly(); boolean isRollbackOnly(); }
使用Spring時(shí),無(wú)論你選擇編程式還是聲明式的事務(wù)管理,定義一個(gè)正確的 PlatformTransactionManager
實(shí)現(xiàn)都是至關(guān)重要的。按照Spring的良好風(fēng)格,這種重要定義都是通過(guò)IoC實(shí)現(xiàn)的。
一般來(lái)說(shuō),選擇PlatformTransactionManager
實(shí)現(xiàn)時(shí)需要知道當(dāng)前的工作環(huán)境,如JDBC、JTA、Hibernate等。下面的例子來(lái)自Spring示例應(yīng)用――jPetStore――中的dataAccessContext-local.xml
文件,其中展示了一個(gè)局部PlatformTransactionManager
實(shí)現(xiàn)是怎么定義的(僅限于純粹JDBC環(huán)境)
我們必須先定義一個(gè)JDBC DataSource
,然后使用Spring的DataSourceTransactionManager
,并傳入指向DataSource
的引用。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
PlatformTransactionManager
bean的定義如下:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
如果我們?cè)贘2EE容器里使用JTA,就像示例中 'dataAccessContext-jta.xml'
文件所示,我們將通過(guò)JNDI和Spring的 JtaTransactionManager
來(lái)獲取一個(gè)容器管理的 DataSource
。JtaTransactionManager
不需要知道 DataSource
和其他特定的資源,因?yàn)樗鼘⑹褂萌萜魈峁┑娜质聞?wù)管理。
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- other <bean/>
definitions here -->
</beans>
上面 'dataSource'
的bean定義使用了 'jee'
名稱(chēng)空間下的 <jndi-lookup/>
標(biāo)簽。想了解更多的配置信息, 請(qǐng)看 附錄?A, XML Schema-based configuration
,關(guān)于 <jee/>
標(biāo)簽的信息,可參考 第?A.2.3?節(jié) “The jee
schema” 節(jié)。
我們也可以很容易地使用Hibernate局部事務(wù),就像下面的Spring框架的 PetClinic 示例應(yīng)用中的例子一樣)。這種情況下,我們需要定義一個(gè)Hibernate的 LocalSessionFactoryBean
,應(yīng)用程序從中獲取到Hibernate Session
實(shí)例。
DataSource
的bean定義同上例類(lèi)似(這里不再展示)。不過(guò),如果是一個(gè)JEE容器提供的 DataSource
,它將由JEE容器自身,而不是Spring框架來(lái)管理事務(wù)。
這種情況中'txManager'
bean的類(lèi)型為 HibernateTransactionManager
。同樣地,DataSourceTransactionManager
需要一個(gè)指向 DataSource
的引用,而 HibernateTransactionManager
需要一個(gè)指向 SessionFactory
的引用。
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mappingResources"> <list> <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=${hibernate.dialect} </value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
我們可以簡(jiǎn)單地使用 JtaTransactionManager
來(lái)處理Hibernate事務(wù)和JTA事務(wù),就像我們處理JDBC,或者任何其它的資源策略一樣。
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
注意任何資源的JTA配置都是這樣的,因?yàn)樗鼈兌际侨质聞?wù),可以支持任何事務(wù)性資源。
在所有這些情況下,應(yīng)用程序代碼根本不需要做任何改動(dòng)。我們僅僅通過(guò)改變配置就可以改變事務(wù)管理方式,即使這些更改是在局部事務(wù)和全局事務(wù)間切換。