Spring應用的幾種事務處理機制html
Java Transaction API和XA協議是Spring經常使用的分佈式事務機制,不過你能夠選擇選擇其餘的實現方式。理想的實現取決於你的應用程序使用何種資源,你願意在性能、安全、系統穩健性、數據完整方面作出何種權衡。在此次JavaWorld大會上,來自SpringSource的David Syer跟你們分享了Spring應用的幾種事務處理機制、三種XA式、四種非XA式事務協議。spring
Spring框架支持Java Transaction API(JTA),這樣應用就能夠脫離Java EE容器,轉而利用分佈式事務以及XA協議。然而即便有這樣的支持,XA開銷是昂貴的,不穩定並且笨重不利於管理,不過一些其餘的應用能夠避免使用XA協議。數據庫
爲了讓你們對所涉及的幾種分佈式事務有所瞭解,我會分析七種事務處理模式,並 給出具體代碼實現。而且從安全或者穩定性入手倒序展現,能夠看看從安全、穩定性出發,如何在通常場景下,保障數據高完整性和原子性。固然隨着話題的深刻, 更多的說明以及限制就會出現。模式也能夠從運行時開銷倒序展現。考慮到全部模式都是結構化或者學術性的,這一點有別於業務模型,所以我不打算展開業務用例 分析,僅僅關注每種模式其少部分代碼如何工做的。編程
儘管只有起初的三種模式涉及到 XA協議,不過從性能角度出發,這些模式或許沒法知足需求。考慮到這些模式無處不在,我不想作過多地擴展,只是對第一種模式作一個簡單的展現。讀完此文,你能夠了解能夠用分佈式事務作些什麼、不能作什麼以及如何、什麼時候避免使用XA,什麼時候必須使用。安全
分佈式事務以及原子性服務器
分佈式事務涉及不止一個事務資源。好比,在關係數據庫和消息中間件之間通訊的鏈接器,一般這些資源擁有相似begin()、rollback()、commit()的API。在此,一個事務資源一般是一個工廠產品,這個工廠一般由底層平臺提供:以數據庫爲例,DataSource提供Connection,或者Java Persistence API(JPA)的EntityManager接口;又如Java Message Service(JMS)提供的Session。session
一個典型的例子,一個JMS消息觸發一次數據庫更新。此過程能夠分解成一時間線,一個成功的交互順序是下面這樣:架構
開啓消息事務併發
接受消息框架
開啓數據庫事務
更新數據庫
提交數據庫事務
提交消息事務
若是數據庫出錯,好比更新時出現諸如違反約束的問題,一個理想的順序應該是下面這個樣子:
開啓消息事務
接受消息
開啓數據庫事務
更新數據庫失敗
回滾數據庫事務
回滾消息事務
在這個案例中,最後的回滾發生後消息返回給中間件,而且在某種程度返回的消息會被其餘事務所接收。一般這是件好事,可能你並無對失敗作記錄。自動重試處理異常機制超出了本文的範疇。
以上兩種時間線中最重要的特性是它們的原子性,造成一個單一的邏輯事務單元,要麼都成功要麼都失敗。
那麼用什麼確保時間線會的順序呢?事務資源之間必須保持某種同步,一旦對某個數據源作提交,要麼都提交了,要麼都回滾。否者整個事務就不缺少原子性。之因此是分佈式事務,是由於有多個數據源,沒有同步就沒有原子性。分佈式事務技術和概念的核心問題都是圍繞資源的同步或者沒法同步展開的。
前三種模式的如下討論都是基於XA協議,考慮到這三種模式分佈普遍,本文不會涉及太多的細節,假若你熟悉XA模式或許願意直接跳到共享事務資源模式。
二階段提交完整XA協議
若是你須要近乎完美的防禦 (close-to-bulletproof)確保你的應用事務在斷電後恢復以及服務器崩潰,完整XA是不二之選。共享資源一般須要作事務同步,在此狀況下,它是一個採用XA協議協調處理過程的信息特殊的事務管理器。在Java領域,從開發者的角度看,這個協議是經過JPA UserTransaction暴露給你們。
基於系統接口,XA做爲一種促成科技(enabling technology)對多數開發人員不可見,所以他們須要知道XA在哪、促成什麼、耗損如何以及如何利用事務資源。事務管理器採用二階段提交(2PC)協議,在確保事務結束前全部資源採用同一個事務結果的同時,也會帶來性能耗損。
如 果是Spring促成的(Spring-enabled),應用會採用Spring的JtaTransactionManager以及Spring聲明式 事務管理,這樣會隱藏到了底層事務同步的具體細節。對於開發人員用沒用XA的差異就在於對工廠資源的配置:DataSource實例,以及應用的事務管理 器。本文會經過一個應用案例(atomikos-db項目)來揭示這個配置,數據庫實例和事務管理器僅是XA或者JTA特定的應用元素。
爲了揭示此案例如何工做,在com.springsource.open.db.下運行這個單元測試。一個簡單的 MulipleDataSourceTests類僅是將數據插入兩個數據源中,而且採用Spring整合支持的特性對事務進行回滾,代碼見清單1:
清單一、事務回滾
@Transactional
@Test
public void testInsertIntoTwoDataSources() throws Exception {
int count = getJdbcTemplate().update(
"INSERT into T_FOOS (id,name,foo_date) values (?,?,null)", 0,
"foo");
assertEquals(1, count);
count = getOtherJdbcTemplate()
.update(
"INSERT into T_AUDITS (id,operation,name,audit_date) values (?,?,?,?)",
0, "INSERT", "foo", new Date());
assertEquals(1, count);
// Changes will roll back after this method exits
}
接着驗證這兩個操做是否同時回滾,代碼清單如清單2:
清單二、回滾驗證
@AfterTransaction
public void checkPostConditions() {
int count = getJdbcTemplate().queryForInt("select count(*) from T_FOOS");
// This change was rolled back by the test framework
assertEquals(0, count);
count = getOtherJdbcTemplate().queryForInt("select count(*) from T_AUDITS");
// This rolled back as well because of the XA
assertEquals(0, count);
}
更進一步理解Spring事務管理如何工做以及如何配置,請參看Spring參考指南。
一階段提交優化XA協議
許多事務管理器採用這種優化模式,能夠避免單一事務資源下的2PC過分開銷,你的應用服務器最好可以判別此種狀況。
協議和最終資源策略
多數XA事務管理器另外一個特性是,不管是單一XA兼 容資源仍是全部資源都XA兼容,事務管理器均能提供相同的恢復保障。它們是經過給資源排序,而且給非XA資源投票實現,假若事務提交失敗,全部其餘的資源 都能回滾。事務有近乎百分百的保障,但缺點是,假若事務失敗,此時不會留下太多信息。換言之,若是要獲取這些信息,須要作一些額外的步驟,好比在一些高級實現。
共享事務資源模式
這個模式不錯,系統全部的事務資源由一個相同的資源提供支持進而移除XA,下降系統的複雜度,提升吞吐量。固然不能拿來處理全部的用例,但倒是如XA般堅固,並且處理速度更加的快。共享事務資源模式做爲一種保障存在與特定的平臺和處理場景中。
一個簡單熟悉的例子就是共享一個數據庫的Connection,它存在於一個對象關係模型(ORM)控件和一個JDBC控件之間。Spring事務管理器就是如此,它支持ORM工具,好比Hibernate、EclipseLink以及Java Persistence API(JPA)。相同的事務能安全的跨越ORM和JDBC控件之間,一般此事務是由service層受事務控制的執行方法所驅動的。
此模式的另一個特色是,消息驅動的單個數據庫更新,如本文初始階段的簡單例子。消 息中間件系統須要存儲這些數據,一般是關係型數據庫。實現這種模式,須要將消息系統指定到相同的用於存儲業務數據的數據庫中。這種模式依賴消息中間件供應 商所提供的存儲策略細節,以便可以將消息中間件配置在相同的數據庫中,並嵌入相同的事務處理。
不是全部的供應商都提供了此種模式,不過一種可替代,幾乎能夠用於任何數據庫的方式,即利用Apache ActiveMQ的傳遞消息,而且插入一個存儲策略進入消息代理中。一旦你知道了其中的訣竅,配置起來很容易的,我會在本文的shared-jms-db 項目案例中演示。此模式的所用的代碼無需關注,它們會在Spring配置中獲得聲明。
名爲 SynchronousMessageTriggerAndRollbackTests 的案例中,單元測試校驗全部與同步消息接收者相關的訊息。 testReceiveMessageUpdateDatabase方法接受兩個消息,接着利用消息插入兩條記錄到數據庫中。若是此方法退出,測試框架回 滾事務,這樣就能校驗消息和數據庫更新是否發生回滾,如清單3所示:
清單三、驗證消息和數據庫更新是否回滾
@AfterTransaction
public void checkPostConditions() {
assertEquals(0, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS"));
List<String> list = getMessages();
assertEquals(2, list.size());
}
配置文件最重要的部分就是ActiveMQ的持久化策略,鏈接消息系統和相同數據源做爲業務數據,Spring JmsTemplate的flag標籤用來接收消息。清單4 展現瞭如何配置ActiveMQ持久化策略:
清單四、ActiveMQ持久化配置
<bean id="connectionFactory" depends-on="brokerService">
<property name="brokerURL" value="vm://localhost?async=false" />
</bean>
<bean id="brokerService" init-method="start" destroy-method="stop">
<property name="persistenceAdapter">
<bean>
<property name="dataSource">
<bean>
<property name="targetDataSource" ref="dataSource"/>
<property name="jmsTemplate" ref="jmsTemplate"/>
</bean>
</property>
<property name="createTablesOnStartup" value="true" />
</bean>
</property>
</bean>
清單5展現了Spring JmsTemplate中用來接收消息的flag標籤:
清單五、設置JmsTemplate事務應用
<bean id="jmsTemplate">
<!-- This is important... -->
<property name="sessionTransacted" value="true" />
</bean>
若 sessionTransacted不爲true,JMS session transaction API就沒法被調用,消息接受者將沒法回滾。最爲重要的是,嵌入的代理包含一個特殊的async=false參數以及DataSource外包類,這樣就能夠確保ActiveMQ擁有同Spring同樣的事務JDBC Connection。
一個共享數據庫源能夠由獨立的單個數據源組成,特別是這些數據源擁有一樣的RDBMS平臺。企業級數 據庫供應商均提供同名概念(the notion of synonyms)支持,表能夠做爲一個同名(synonyms)聲明於多個schema中。藉助這個手段,分佈在不一樣物理平臺上的數據,能夠都可 JDBC client贊成Connection事務管理。好比在一個真實的系統中,採用ActiveMQ共享資源模式實現,一般須要爲消息和業務數據建立同名。
性能和JDBCPersistenceAdapter
ActiveMQ 社區的一些開發人員表示JDBCPersistenceAdapter會引起性能問題。然而,許多項目和上線系統採用ActiveMQ與關係型數據庫搭配使 用。在這些案例中,公認的是日誌版本的適配器能夠用來提供性能,固然這對共享資源模式來講是不利的,由於日誌自己就是一個新的事務資源。然而,對於 JDBCPersistenceAdapter你們衆說紛紜,見解不一。確實,有理由相信採用共享資源或許能提升日誌案例的性能。這個一結論來自 Sping以及AtiveMQ工程師團隊的研究。
非消息場景(多個數據庫)的另外一種共享資源技術就是,在RDBMS平臺一級利用Oracle數據庫連接一個特徵到兩個數據庫schema中。或許這須要改變應用代碼,或者建立同名,由於表的別名會指向一個已連接數據庫,此數據庫包含連接的名稱。
最大努力一次提交模式
開發人員必須知道,最大努力一次提交模式應用至關的廣泛,可是在一些場景並不適用。這是一種非XA模式,它包含一 個同步大量資源單一相提交(single-phase commit)。參與者應該意識到這種折中,若是不用兩階段提交,那最大努力一次提交模式的安全性不如XA事務但也是至關不錯。許多海量數據、大吞吐量事 務處理系統用最大努力一次提交模式提升性能。
最基本的理念就是在單一事務中儘量的延遲全部資源的提交,這樣惟一可能發生錯誤的就是基礎組件,而非業務處理錯誤。 採用最大努力一次提交模式的系統假定基礎組件出錯的可能性很是小,所以可以承受風險得到較高的吞吐量收益。若是業務處理服務也被設計爲一個幕等式 (idempotent),發生錯誤的可能性也很小。(譯者注:幕等式是數學和計算機科學特定運算的一個特性,應用初始化之後屢次操做其結果都不會再發生改變)
爲了幫助你們更好的理解這個模式分析失敗結果,我會用消息驅動數據庫更新做爲例子來加以說明。
本事務中兩個資源將被統計、而且計算。消息事務在一個數據庫以前開啓,而後逆序結束。成功的順序或許和本文開始的時候如出一轍:
開啓消息事務
接受消息
開啓數據庫事務
更新數據庫
提交數據庫事務
提交消息事務
準確的說,此順序前四個步驟都不重要,重要的是消息必須在數據庫更新以前被接受,而且每一個事務必須在對應的資源被調用以前開啓,所以合理的順序應該以下:
開啓消息事務
開啓數據庫事務
接受消息
更新數據庫
提交數據庫事務
提交消息事務
關鍵點是最後兩步很重要,它們必須放在最後按順序執行。按序之因此重要,其自己就是一個技術問題,不過這個順序是有業務需 要決定的。這個順序告訴開發者,其中的一個事務資源是特殊的,這個資源包含了如何在其餘資源上運做的指令。這是一個業務順序:系統不能自動告知走事務到哪一步了。即便消息和數據庫是兩個資源,事務也經常遵循這一流程。按序之因此重要,是由於事務必須處理失敗案例。迄今最多見的失敗案例是,諸如壞數據、編程錯誤等失敗的業務處理。本例中,這兩個事務很容易用來相應一個異常而且回滾。這樣,業務數據的完成性獲得保障,時間線與本文開始列出的理想失敗案例神似。
引起回滾機制的精確性不是很重要的,這樣的機制有好一些。最重要的是,提交或者回滾必須按照資源中業務順序的逆序發生。在一個應用案例中,消息事務必須在最後提交,由於處理業務的指令包含在這個資源中,這是由於,不多有失敗案例 其第一次提交成功,第二次失敗。在這個點上,全部設計業務處理的部分都已完成,那惟一能引發部分失敗的因素,可能消息中間件的基礎問題。
注意若是 數據庫資源提交失敗,那麼事務最終會發生回滾。因此是說非原子性失敗模型(failure mode)其第一個事務會提交,第二個事務發生回滾。一般,事務中有n個資源,那麼就存在n-1個這樣的失敗模型,這會致使一個子事務回滾後,其它一些資源處在提交後的不一致狀態。在消息數據庫用例中,失敗模型的結局是,消息會回滾,而後是其餘的事務,即便其餘這些事務都經成功處理;能夠判定最糟糕的事情 就是重複消息(duplicate message)被傳遞過來。什麼是重複消息呢?一般狀況下,事務中的早期資源被認爲是包含有後續資源處理流程的訊息,所以失敗模型的結果能夠被認爲就是重複消息。
一些富有冒險精神的人認爲重複消息發生的可能性微乎其微,所以懶得去預測這些消息。然而,爲了更加確信業務數據是準確性和一致性,仍是須要在業務邏輯層面對 此有清晰地認識。 若是懷疑重複消息可能發生,那麼必須覈實,業務處理過程是否處理過數據,在處理數據以前是否什麼都沒作。這個特定的說明有時指幕等業務服務模型 (Idempotent Business Service pattern)。
相關案例包括兩個採用此模型的同步事務資源例子,我會在後面作一一分析,以及一些其它選項。
Spring和消息驅動POJO
案例best-jms-db項目中的代碼,開發人員採用主流配置,這樣就可使用最大努力一次提交模式。具體的作法是這樣的,經過一個異步的監聽器將消息傳給一個隊列,並將此數據插入 數據庫表中。
TransactionAwareConnectionFactoryProxy 是Spring的一個存儲控件,應用於這個模式中,也是最關鍵的組成部分。放棄採用供應商提供的粗顆粒度的 ConnectionFactory,configuration採用裝飾模式包裝了一個ConnectionFactory,用它來處理事務同步問題。 具體配置見jms-context.xml,以下清單6所示:
清單六、配置一個TransactionAwareConnectionFactoryProxy去包裝一個供應商提供的JMS ConnectionFactory
<bean id="connectionFactory">
<property name="targetConnectionFactory">
<bean depends-on="brokerService">
<property name="brokerURL" value="vm://localhost"/>
</bean>
</property>
<property name="synchedLocalTransactionAllowed" value="true" />
</bean>
ConnectionFactory 無需知道哪一個事務管理器與其同步,每一時刻僅有一個事務處在活動(active)狀態。這些是由Spring內部在處理。事務驅動是由配置在data- source-context.xml中的DataSourceTransactionManager完成的,事務管理器必須由輪詢和接受消息的JMS監聽器容器監控。
<jms:listener-container transaction-manager="transactionManager" >
<jms:listener destination="async" ref="fooHandler" method="handle"/>
</jms:listener-container>
fooHandler和方法會告知監聽器容器某個具體的控件的具體方法獲得調用,當一個消息達到」異步」隊列。handler是如此實現的,接受一個String做爲參數消息,並將其做爲數據插入記錄中。
public void handle(String msg) {
jdbcTemplate.update(
"INSERT INTO T_FOOS (ID, name, foo_date) values (?, ?,?)", count.getAndIncrement(), msg, new Date());
}
爲了模擬失敗,代碼用一個FailureSimulator切面,它會檢查消息內容是否真的失敗;如清單7所示,在FooHandler在事務結束以前,處理消息以後,maybeFail()方法獲得調用,因此它能影響事務的結果。
清單七、maybeFail()方法
@AfterReturning("execution( ..*Handler+.handle(String)) && args(msg)")
public void maybeFail(String msg) {
if (msg.contains("fail")) {
if (msg.contains("partial")) {
simulateMessageSystemFailure();
} else {
simulateBusinessProcessingFailure();
}
}
}
simulateBusinessProcessingFailure() 方法會拋出DataAccessException,就像數據庫訪問真的失敗。一旦這個方法被調用,最理想的結局是全部的數據庫以及消息事務都能回滾。 這個場景在案例項目AsynchronousMessageTriggerAndRollbackTests單元測試獲得測試。
simulateMessageSystemFailure() 方法經過破壞底層的JMS Session來模擬消息系統失敗。預期的結果是事務部分提交:數據庫提交了,但消息回滾。這個在 synchronousMessageTriggerAndPartialRollbackTests單元測試驗證過。
一樣,在AsynchronousMessageTriggerSunnyDayTests類中,包含一個全部事務成功提交的單元測試。
相 同的JMS配置,相同的業務邏輯一樣能夠用在同步的環境中,消息由存儲在業務邏輯中的阻塞請求所接收,而非監聽器容器。此方法在best-jms-db案 例項目中獲得展現。 sunny-day case以及事務所有回滾分別在SynchronousMessageTriggerSunnyDayTests和 SynchronousMessageTriggerAndRollbackTests獲得測試。
鏈式事務管理器
在其餘的最大努力一階段提交模式案例中,一個粗糙的事務管理器實現僅僅是將一系列其餘的事務管理器連接在一塊兒,去實現事務同步。假若業務處理成功,全部的事務將會提交, 不然它們都能回滾。
ChainedTransactionManager 接受一系列其餘的事務管理器做爲注入屬性,如清單8所示:
清單八、配置
<bean id="transactionManager">
<property name="transactionManagers">
<list>
<bean>
<property name="dataSource" ref="dataSource" />
</bean>
<bean>
<property name="dataSource" ref="otherDataSource" />
</bean>
</list>
</property>
</bean>
此配置簡單的測試,僅是同時插入數據到兩個數據庫,回滾,同時確保兩個運行回滾到最初狀態。此實現做爲存在MulipleDataSourceTests中的一個單元測試,如同XA案例中的 atomikos-db項目。假若回滾沒有同步,有事務提交了,那測試就算失敗。
記住,資源順序很重要,它們是嵌套的,提交或者回滾以它們參與的相反順序進行。其中一個事務最爲特別:若是存在問題,最重要的事務會回滾,即使是這問題是一個資源失敗。 一樣,testInsertWithCheckForDuplicates()測試方法展現了幕等式業務處理如何從部分失敗中保護系統,此實現做爲一個裏層資源(otherDataSource)中業務運算防護檢測。
int count = otherJdbcTemplate.update("UPDATE T_AUDITS ... WHERE id=, ...?");
if (count == 0) { count = otherJdbcTemplate.update("INSERT into T_AUDITS ...", ...); }
update首先嚐試和一個where子句執行,不出意外,update中的數據會插入數據庫中。本例中的幕等式處理一個額外的花銷是sunny-day case中額外的查詢,這個額外的花銷在複雜的每一個事務執行多個查詢的業務處理中微乎其微。
其餘選擇
案例中的ChainedTransactionManager擁有簡潔優點,並且擴展優化已作的很好。另外一個方式是, 當第二個資源加入時,利用Spring的TransactionSychronization API給當前事務 註冊一個回調函數,此方式在best-jms-db案例中,最大的特色是TransactionAwareConnectionFactory和一個 DataSourceTransactionManager的結合。利用TransactionSynchronizationManager,這個特殊的案例能夠擴展而且泛化到包含non-JMS的資源中。這樣理論上有個優點,就是隻有加入事務的資源獲得支持,而非鏈上的 全部資源。然而配置依舊須要監聽某個潛在的事務與之對應的資源。
一樣,Spring工程師團隊考慮將最大努力一階段提交事務管理器特性做爲Spring核心。你能夠在JJRA issue中投票,若是你喜歡這種模式,但願Spring中顯示以及更加透明地支持此種模式。
非事務訪問模式
非事務訪問模式須要一個特殊的業務處理,這樣纔有意義。理想的狀態是有時,其中一些你須要訪問的資源邊緣化,一點都不須要事務。好比,或許你須要將一行數據插入一個 審覈表中,此操做是獨立的,和業務事務是否成功無關。僅僅記錄試圖作了某事。更廣泛的場景,人們高估了他們須要對其中一個資源作讀寫的頻次,事實上,只有 訪問就很好了。 不然,寫操做須要獲得很好地控制,所以若是發生任何錯誤,寫操做能夠被記錄下來或者忽略。
在以上的案例中資源恰當地原理全局事務,但仍然有其本身的本地事務,本地事務無需與其餘發生的事情保持同步。若是你使用的是Spring,主要的事務由一個PlatformTransactionManager驅動, 邊緣資源或許是一個數據庫Connection,它來自一個不受事務管理器控制的DataSource。每一次訪問邊緣資源須要將缺省環境設爲 autoCommit=true。updates對讀操做不可見,前者能夠與其餘非提交事務併發進行,但寫操做帶來的影響一般對其餘操做來講是當即可見的。
這個模式須要更多精細地分析,以及更多自信去涉及業務處理,但它同最大努力一階段提交沒 什麼區別。當任何事情出錯,一個通用的補償事務服務對多數項目來講太過龐大。不過簡單的用例所涉及的服務,它是幕等式的僅僅執行一個寫的操做,這種現象再 普通不過了。這些是非事務策略的理想場景。
Wing-and-a-Prayer:一種反模式
最後一種模式是一種反模式,它出現這樣一個場景中,開發者不理解或者沒有意識到他們已經存在一個分佈式事務時。無需顯示的調用底層的資源事務API,你不確 定全部的資源是否在一個事務中。假若用的是一個Spring事務管理器而非JtaTransactionManager,此管理器會將一個事務資源加入其中。這個事務管理器將會攔截Spring聲明事務管理特性的執行方法,好比@Transactional;其餘的資源不會註冊到相同的事務中。一般的結局 是任何事情都運轉正常,不過很快用戶會發現存在一個異常,其中一個資源沒有回滾。一個典型的錯誤致使的問題是利用一個 DataSourceTransactionManager以及一個利用Hibernate實現的倉庫。
該用哪一個模式呢?
我會經過分析已介紹過的模式其利弊,幫助你們作出取捨。第一步是分析你的系統是否須要分佈式事務。一個必須但不充分條件是,存在不止一個事務資源的單一處理。充分條件是這些資源都在一個單獨的用例中,一般由系統架構的service層調用來驅動。
若是你不認爲這是分佈式事務,那最好採用Wing-and-a-Prayer模式,接着你會看見數據應該回滾但沒有。或許你會看到這種影響從失敗發生直至其下游一直存在,並且很難追溯回去。Wing-and-a-Prayer的 使用也可能會開發人員所疏忽,他們認爲受到了XA保障,其實並沒與配置底層資源加入到事務中。我曾經作過一個這樣的項目,數據庫是其餘人員搭建的,他們在 安裝數據庫的過程當中關閉了XA支持。運行了個把月沒有任何問題,接着各類奇怪的失敗開始侵入業務處理中,須要花很長的時間去找出問題。
若是是一個包含異質資源的簡單用例,你能夠分析甚至作一些重構,那麼非事務訪問模式或 許是個不錯的選擇,特別是其中一個幾乎是只讀資源,雙檢測確保寫操做。即使是失敗了,非事務資源中的數據在業務術語中必須有意義。審覈、版本控制、甚至日 志信息能很好的切入到此目錄中,失敗變得相對很日常—-任什麼時候間真實事務中的任何事情均可回滾,但你需確信這樣作不存在負面影響就好。
對系統而言,最大努力一階段提交須要通用的失敗保護機制,但有不存在2PC那麼大的開銷,並且性能獲得極大的提高。相對非事務資源,它的創建須要更多的技巧,但無需太多的分析, 一般應用於更加通用的數據類型中。完成數據一致性的某些特性,須要保障業務處理對外層資源(」outer」 resources:第一個提交的資源)而言是幕等式。消息驅動的數據庫更新就是一個完美的例子,而且在Spring中獲得很好的支持。不常見的場景須要一些額外的框架代碼,這些代碼終究會成爲Spring的一部分。
共享資源模式是一種特定的例子,一般涉及一個特定的類型和平臺兩個資源,好比,ActiveMQ和任何一個RDBMS或者OracleAQ與一個Oracle數據庫共存。這樣作最大的收益是至關的靈活以及出色的性能。
Full XA with 2PC是一種通用模式,在應對多個異質資源事務 失敗時提供很好的無憂保證。不利的是它的開銷很大,須要遵循特定的I/O協議和特定的平臺。有開源的JTA實現,提供了一種擺脫應用服務器的方式,但多數 開發人員依舊認爲它們並不是最好。能夠確信的是,人們花更多的時間去思考系統的事務界限,會更傾向於使用他們並不那麼須要的JTA和XA。至少使用 Spring的開發人員,他們的業務邏輯無需知道事務如何被處理的,暫時無需考慮平臺選擇的問題。
來源: ImportNew - 喬永琪
連接:http://www.importnew.com/15812.html