Spring應(yīng)用的幾種事務(wù)處理機制Java Transaction API和XA協(xié)議是Spring常用的分布式事務(wù)機制,不過你可以選擇選擇其他的實現(xiàn)方式。理想的實現(xiàn)取決于你的應(yīng)用程序使用何種資源,你愿意在性能、安全、系統(tǒng)穩(wěn)健性、數(shù)據(jù)完整方面做出何種權(quán)衡。在這次JavaWorld大會上,來自SpringSource的David Syer跟大家分享了Spring應(yīng)用的幾種事務(wù)處理機制、三種XA式、四種非XA式事務(wù)協(xié)議。 Spring框架支持Java Transaction API(JTA),這樣應(yīng)用就可以脫離Java EE容器,轉(zhuǎn)而利用分布式事務(wù)以及XA協(xié)議。然而即使有這樣的支持,XA開銷是昂貴的,不穩(wěn)定而且笨重不利于管理,不過一些其他的應(yīng)用可以避免使用XA協(xié)議。 為了讓大家對所涉及的幾種分布式事務(wù)有所了解,我會分析七種事務(wù)處理模式,并 給出具體代碼實現(xiàn)。并且從安全或者穩(wěn)定性入手倒序展示,可以看看從安全、穩(wěn)定性出發(fā),如何在一般場景下,保障數(shù)據(jù)高完整性和原子性。當然隨著話題的深入, 更多的說明以及限制就會出現(xiàn)。模式也可以從運行時開銷倒序展示??紤]到所有模式都是結(jié)構(gòu)化或者學(xué)術(shù)性的,這一點有別于業(yè)務(wù)模型,因此我不打算展開業(yè)務(wù)用例 分析,僅僅關(guān)注每種模式其少部分代碼如何工作的。 盡管只有起初的三種模式涉及到 XA協(xié)議,不過從性能角度出發(fā),這些模式或許無法滿足需求。考慮到這些模式無處不在,我不想做過多地擴展,只是對第一種模式做一個簡單的展示。讀完此文,你可以了解可以用分布式事務(wù)做些什么、不能做什么以及如何、何時避免使用XA,何時必須使用。 分布式事務(wù)以及原子性分布式事務(wù)涉及不止一個事務(wù)資源。比如,在關(guān)系數(shù)據(jù)庫和消息中間件之間通信的連接器,通常這些資源擁有類似begin()、rollback()、commit()的API。在此,一個事務(wù)資源通常是一個工廠產(chǎn)品,這個工廠通常由底層平臺提供:以數(shù)據(jù)庫為例,DataSource提供Connection,或者Java Persistence API(JPA)的EntityManager接口;又如Java Message Service(JMS)提供的Session。 一個典型的例子,一個JMS消息觸發(fā)一次數(shù)據(jù)庫更新。此過程可以分解成一時間線,一個成功的交互順序是下面這樣:
如果數(shù)據(jù)庫出錯,比如更新時出現(xiàn)諸如違反約束的問題,一個理想的順序應(yīng)該是下面這個樣子:
在這個案例中,最后的回滾發(fā)生后消息返回給中間件,并且在某種程度返回的消息會被其他事務(wù)所接收。通常這是件好事,可能你并沒有對失敗做記錄。自動重試處理異常機制超出了本文的范疇。 以上兩種時間線中最重要的特性是它們的原子性,形成一個單一的邏輯事務(wù)單元,要么都成功要么都失敗。 那么用什么確保時間線會的順序呢?事務(wù)資源之間必須保持某種同步,一旦對某個數(shù)據(jù)源做提交,要么都提交了,要么都回滾。否者整個事務(wù)就不缺乏原子性。之所以是分布式事務(wù),是因為有多個數(shù)據(jù)源,沒有同步就沒有原子性。分布式事務(wù)技術(shù)和概念的核心問題都是圍繞資源的同步或者無法同步展開的。 前三種模式的以下討論都是基于XA協(xié)議,考慮到這三種模式分布廣泛,本文不會涉及太多的細節(jié),倘若你熟悉XA模式或許愿意直接跳到共享事務(wù)資源模式。 二階段提交完整XA協(xié)議如果你需要近乎完美的防護 (close-to-bulletproof)確保你的應(yīng)用事務(wù)在斷電后恢復(fù)以及服務(wù)器崩潰,完整XA是不二之選。共享資源通常需要做事務(wù)同步,在此情況下,它是一個采用XA協(xié)議協(xié)調(diào)處理過程的信息特殊的事務(wù)管理器。在Java領(lǐng)域,從開發(fā)者的角度看,這個協(xié)議是通過JPA UserTransaction暴露給大家。 基于系統(tǒng)接口,XA作為一種促成科技(enabling technology)對多數(shù)開發(fā)人員不可見,因此他們需要知道XA在哪、促成什么、耗損如何以及如何利用事務(wù)資源。事務(wù)管理器采用二階段提交(2PC)協(xié)議,在確保事務(wù)結(jié)束前所有資源采用同一個事務(wù)結(jié)果的同時,也會帶來性能耗損。 如 果是Spring促成的(Spring-enabled),應(yīng)用會采用Spring的JtaTransactionManager以及Spring聲明式 事務(wù)管理,這樣會隱藏到了底層事務(wù)同步的具體細節(jié)。對于開發(fā)人員用沒用XA的差別就在于對工廠資源的配置:DataSource實例,以及應(yīng)用的事務(wù)管理 器。本文會通過一個應(yīng)用案例(atomikos-db項目)來揭示這個配置,數(shù)據(jù)庫實例和事務(wù)管理器僅是XA或者JTA特定的應(yīng)用元素。 為了揭示此案例如何工作,在com.springsource.open.db.下運行這個單元測試。一個簡單的 MulipleDataSourceTests類僅是將數(shù)據(jù)插入兩個數(shù)據(jù)源中,并且采用Spring整合支持的特性對事務(wù)進行回滾,代碼見清單1: 清單1、事務(wù)回滾
接著驗證這兩個操作是否同時回滾,代碼清單如清單2: 清單2、回滾驗證
更進一步理解Spring事務(wù)管理如何工作以及如何配置,請參看Spring參考指南。 一階段提交優(yōu)化XA協(xié)議許多事務(wù)管理器采用這種優(yōu)化模式,可以避免單一事務(wù)資源下的2PC過度開銷,你的應(yīng)用服務(wù)器最好能夠判別此種情況。 協(xié)議和最終資源策略多數(shù)XA事務(wù)管理器另一個特性是,不論是單一XA兼 容資源還是所有資源都XA兼容,事務(wù)管理器均能提供相同的恢復(fù)保障。它們是通過給資源排序,并且給非XA資源投票實現(xiàn),倘若事務(wù)提交失敗,所有其他的資源 都能回滾。事務(wù)有近乎百分百的保障,但缺點是,倘若事務(wù)失敗,此時不會留下太多信息。換言之,如果要獲取這些信息,需要做一些額外的步驟,比如在一些高級實現(xiàn)。 共享事務(wù)資源模式這個模式不錯,系統(tǒng)所有的事務(wù)資源由一個相同的資源提供支持進而移除XA,降低系統(tǒng)的復(fù)雜度,提高吞吐量。當然不能拿來處理所有的用例,但卻是如XA般堅固,而且處理速度更加的快。共享事務(wù)資源模式作為一種保障存在與特定的平臺和處理場景中。 一個簡單熟悉的例子就是共享一個數(shù)據(jù)庫的Connection,它存在于一個對象關(guān)系模型(ORM)控件和一個JDBC控件之間。Spring事務(wù)管理器就是如此,它支持ORM工具,比如Hibernate、EclipseLink以及Java Persistence API(JPA)。相同的事務(wù)能安全的跨越ORM和JDBC控件之間,通常此事務(wù)是由service層受事務(wù)控制的執(zhí)行方法所驅(qū)動的。 此模式的另外一個特點是,消息驅(qū)動的單個數(shù)據(jù)庫更新,如本文初始階段的簡單例子。消 息中間件系統(tǒng)需要存儲這些數(shù)據(jù),通常是關(guān)系型數(shù)據(jù)庫。實現(xiàn)這種模式,需要將消息系統(tǒng)指定到相同的用于存儲業(yè)務(wù)數(shù)據(jù)的數(shù)據(jù)庫中。這種模式依賴消息中間件供應(yīng) 商所提供的存儲策略細節(jié),以便能夠?qū)⑾⒅虚g件配置在相同的數(shù)據(jù)庫中,并嵌入相同的事務(wù)處理。 不是所有的供應(yīng)商都提供了此種模式,不過一種可替代,幾乎可以用于任何數(shù)據(jù)庫的方式,即利用Apache ActiveMQ的傳遞消息,并且插入一個存儲策略進入消息代理中。一旦你知道了其中的訣竅,配置起來很容易的,我會在本文的shared-jms-db 項目案例中演示。此模式的所用的代碼無需關(guān)注,它們會在Spring配置中得到聲明。 名為 SynchronousMessageTriggerAndRollbackTests 的案例中,單元測試校驗所有與同步消息接收者相關(guān)的訊息。 testReceiveMessageUpdateDatabase方法接受兩個消息,接著利用消息插入兩條記錄到數(shù)據(jù)庫中。如果此方法退出,測試框架回 滾事務(wù),這樣就能校驗消息和數(shù)據(jù)庫更新是否發(fā)生回滾,如清單3所示: 清單3、驗證消息和數(shù)據(jù)庫更新是否回滾
配置文件最重要的部分就是ActiveMQ的持久化策略,連接消息系統(tǒng)和相同數(shù)據(jù)源作為業(yè)務(wù)數(shù)據(jù),Spring JmsTemplate的flag標簽用來接收消息。清單4 展示了如何配置ActiveMQ持久化策略: 清單4、ActiveMQ持久化配置
清單5展示了Spring JmsTemplate中用來接收消息的flag標簽: 清單5、設(shè)置JmsTemplate事務(wù)應(yīng)用
若 sessionTransacted不為true,JMS session transaction API就無法被調(diào)用,消息接受者將無法回滾。最為重要的是,嵌入的代理包含一個特殊的async=false參數(shù)以及DataSource外包類,這樣就可以確保ActiveMQ擁有同Spring一樣的事務(wù)JDBC Connection。 一個共享數(shù)據(jù)庫源可以由獨立的單個數(shù)據(jù)源組成,特別是這些數(shù)據(jù)源擁有同樣的RDBMS平臺。企業(yè)級數(shù) 據(jù)庫供應(yīng)商均提供同名概念(the notion of synonyms)支持,表可以作為一個同名(synonyms)聲明于多個schema中。借助這個手段,分布在不同物理平臺上的數(shù)據(jù),可以均可 JDBC client同意Connection事務(wù)管理。比如在一個真實的系統(tǒng)中,采用ActiveMQ共享資源模式實現(xiàn),通常需要為消息和業(yè)務(wù)數(shù)據(jù)創(chuàng)建同名。 性能和JDBCPersistenceAdapterActiveMQ 社區(qū)的一些開發(fā)人員表示JDBCPersistenceAdapter會引發(fā)性能問題。然而,許多項目和上線系統(tǒng)采用ActiveMQ與關(guān)系型數(shù)據(jù)庫搭配使 用。在這些案例中,公認的是日志版本的適配器可以用來提供性能,當然這對共享資源模式來說是不利的,因為日志本身就是一個新的事務(wù)資源。然而,對于 JDBCPersistenceAdapter大家眾說紛紜,看法不一。確實,有理由相信采用共享資源或許能提高日志案例的性能。這個一結(jié)論來自 Sping以及AtiveMQ工程師團隊的研究。 非消息場景(多個數(shù)據(jù)庫)的另一種共享資源技術(shù)就是,在RDBMS平臺一級利用Oracle數(shù)據(jù)庫鏈接一個特征到兩個數(shù)據(jù)庫schema中。或許這需要改變應(yīng)用代碼,或者創(chuàng)建同名,因為表的別名會指向一個已鏈接數(shù)據(jù)庫,此數(shù)據(jù)庫包含鏈接的名稱。 最大努力一次提交模式開發(fā)人員必須知道,最大努力一次提交模式應(yīng)用相當?shù)钠毡椋窃谝恍﹫鼍安⒉贿m用。這是一種非XA模式,它包含一 個同步大量資源單一相提交(single-phase commit)。參與者應(yīng)該意識到這種折中,如果不用兩階段提交,那最大努力一次提交模式的安全性不如XA事務(wù)但也是相當不錯。許多海量數(shù)據(jù)、大吞吐量事 務(wù)處理系統(tǒng)用最大努力一次提交模式提高性能。 最基本的理念就是在單一事務(wù)中盡可能的延遲所有資源的提交,這樣唯一可能發(fā)生錯誤的就是基礎(chǔ)組件,而非業(yè)務(wù)處理錯誤。 采用最大努力一次提交模式的系統(tǒng)假定基礎(chǔ)組件出錯的可能性非常小,因此能夠承受風(fēng)險獲得較高的吞吐量收益。如果業(yè)務(wù)處理服務(wù)也被設(shè)計為一個幕等式 (idempotent),發(fā)生錯誤的可能性也很小。(譯者注:幕等式是數(shù)學(xué)和計算機科學(xué)特定運算的一個特性,應(yīng)用初始化以后多次操作其結(jié)果都不會再發(fā)生改變) 為了幫助大家更好的理解這個模式分析失敗結(jié)果,我會用消息驅(qū)動數(shù)據(jù)庫更新作為例子來加以說明。 本事務(wù)中兩個資源將被統(tǒng)計、并且計算。消息事務(wù)在一個數(shù)據(jù)庫之前開啟,然后逆序結(jié)束。成功的順序或許和本文開始的時候一模一樣:
準確的說,此順序前四個步驟都不重要,重要的是消息必須在數(shù)據(jù)庫更新之前被接受,并且每個事務(wù)必須在對應(yīng)的資源被調(diào)用之前開啟,因此合理的順序應(yīng)該如下:
關(guān)鍵點是最后兩步很重要,它們必須放在最后按順序執(zhí)行。按序之所以重要,其本身就是一個技術(shù)問題,不過這個順序是有業(yè)務(wù)需 要決定的。這個順序告訴開發(fā)者,其中的一個事務(wù)資源是特殊的,這個資源包含了如何在其他資源上運作的指令。這是一個業(yè)務(wù)順序:系統(tǒng)不能自動告知走事務(wù)到哪一步了。即使消息和數(shù)據(jù)庫是兩個資源,事務(wù)也常常遵循這一流程。按序之所以重要,是因為事務(wù)必須處理失敗案例。迄今最常見的失敗案例是,諸如壞數(shù)據(jù)、編程錯誤等失敗的業(yè)務(wù)處理。本例中,這兩個事務(wù)很容易用來相應(yīng)一個異常并且回滾。這樣,業(yè)務(wù)數(shù)據(jù)的完成性得到保障,時間線與本文開始列出的理想失敗案例神似。 引發(fā)回滾機制的精確性不是很重要的,這樣的機制有好一些。最重要的是,提交或者回滾必須按照資源中業(yè)務(wù)順序的逆序發(fā)生。在一個應(yīng)用案例中,消息事務(wù)必須在最后提交,因為處理業(yè)務(wù)的指令包含在這個資源中,這是因為,很少有失敗案例 其第一次提交成功,第二次失敗。在這個點上,所有設(shè)計業(yè)務(wù)處理的部分都已完成,那唯一能引起部分失敗的因素,可能消息中間件的基礎(chǔ)問題。 注意如果 數(shù)據(jù)庫資源提交失敗,那么事務(wù)最終會發(fā)生回滾。所以是說非原子性失敗模型(failure mode)其第一個事務(wù)會提交,第二個事務(wù)發(fā)生回滾。通常,事務(wù)中有n個資源,那么就存在n-1個這樣的失敗模型,這會導(dǎo)致一個子事務(wù)回滾后,其它一些資源處在提交后的不一致狀態(tài)。在消息數(shù)據(jù)庫用例中,失敗模型的結(jié)局是,消息會回滾,然后是其他的事務(wù),即使其他這些事務(wù)都經(jīng)成功處理;可以斷定最糟糕的事情 就是重復(fù)消息(duplicate message)被傳遞過來。什么是重復(fù)消息呢?通常情況下,事務(wù)中的早期資源被認為是包含有后續(xù)資源處理流程的訊息,因此失敗模型的結(jié)果可以被認為就是重復(fù)消息。 一 些富有冒險精神的人認為重復(fù)消息發(fā)生的可能性微乎其微,因此懶得去預(yù)測這些消息。然而,為了更加確信業(yè)務(wù)數(shù)據(jù)是準確性和一致性,還是需要在業(yè)務(wù)邏輯層面對 此有清晰地認識。 如果懷疑重復(fù)消息可能發(fā)生,那么必須核實,業(yè)務(wù)處理過程是否處理過數(shù)據(jù),在處理數(shù)據(jù)之前是否什么都沒做。這個特定的說明有時指幕等業(yè)務(wù)服務(wù)模型 (Idempotent Business Service pattern)。 相關(guān)案例包括兩個采用此模型的同步事務(wù)資源例子,我會在后面做一一分析,以及一些其它選項。 Spring和消息驅(qū)動POJO案例best-jms-db項目中的代碼,開發(fā)人員采用主流配置,這樣就可以使用最大努力一次提交模式。具體的做法是這樣的,通過一個異步的監(jiān)聽器將消息傳給一個隊列,并將此數(shù)據(jù)插入 數(shù)據(jù)庫表中。 TransactionAwareConnectionFactoryProxy 是Spring的一個存儲控件,應(yīng)用于這個模式中,也是最關(guān)鍵的組成部分。放棄采用供應(yīng)商提供的粗顆粒度的 ConnectionFactory,configuration采用裝飾模式包裝了一個ConnectionFactory,用它來處理事務(wù)同步問題。 具體配置見jms-context.xml,如下清單6所示: 清單6、配置一個TransactionAwareConnectionFactoryProxy去包裝一個供應(yīng)商提供的JMS ConnectionFactory
ConnectionFactory 無需知道哪個事務(wù)管理器與其同步,每一時刻僅有一個事務(wù)處在活動(active)狀態(tài)。這些是由Spring內(nèi)部在處理。事務(wù)驅(qū)動是由配置在data- source-context.xml中的DataSourceTransactionManager完成的,事務(wù)管理器必須由輪詢和接受消息的JMS監(jiān)聽器容器監(jiān)控。
fooHandler和方法會告知監(jiān)聽器容器某個具體的控件的具體方法得到調(diào)用,當一個消息達到”異步”隊列。handler是如此實現(xiàn)的,接受一個String作為參數(shù)消息,并將其作為數(shù)據(jù)插入記錄中。
為了模擬失敗,代碼用一個FailureSimulator切面,它會檢查消息內(nèi)容是否真的失敗;如清單7所示,在FooHandler在事務(wù)結(jié)束之前,處理消息之后,maybeFail()方法得到調(diào)用,所以它能影響事務(wù)的結(jié)果。 清單7、maybeFail()方法
simulateBusinessProcessingFailure() 方法會拋出DataAccessException,就像數(shù)據(jù)庫訪問真的失敗。一旦這個方法被調(diào)用,最理想的結(jié)局是所有的數(shù)據(jù)庫以及消息事務(wù)都能回滾。 這個場景在案例項目AsynchronousMessageTriggerAndRollbackTests單元測試得到測試。 simulateMessageSystemFailure() 方法通過破壞底層的JMS Session來模擬消息系統(tǒng)失敗。預(yù)期的結(jié)果是事務(wù)部分提交:數(shù)據(jù)庫提交了,但消息回滾。這個在 synchronousMessageTriggerAndPartialRollbackTests單元測試驗證過。 同樣,在AsynchronousMessageTriggerSunnyDayTests類中,包含一個所有事務(wù)成功提交的單元測試。 相 同的JMS配置,相同的業(yè)務(wù)邏輯同樣可以用在同步的環(huán)境中,消息由存儲在業(yè)務(wù)邏輯中的阻塞請求所接收,而非監(jiān)聽器容器。此方法在best-jms-db案 例項目中得到展示。 sunny-day case以及事務(wù)全部回滾分別在SynchronousMessageTriggerSunnyDayTests和 SynchronousMessageTriggerAndRollbackTests得到測試。 鏈式事務(wù)管理器在其他的最大努力一階段提交模式案例中,一個粗糙的事務(wù)管理器實現(xiàn)僅僅是將一系列其他的事務(wù)管理器鏈接在一起,去實現(xiàn)事務(wù)同步。倘若業(yè)務(wù)處理成功,所有的事務(wù)將會提交, 否則它們都能回滾。 ChainedTransactionManager 接受一系列其他的事務(wù)管理器作為注入屬性,如清單8所示: 清單8、配置
此配置簡單的測試,僅是同時插入數(shù)據(jù)到兩個數(shù)據(jù)庫,回滾,同時確保兩個運行回滾到最初狀態(tài)。此實現(xiàn)作為存在MulipleDataSourceTests中的一個單元測試,如同XA案例中的 atomikos-db項目。倘若回滾沒有同步,有事務(wù)提交了,那測試就算失敗。 記 住,資源順序很重要,它們是嵌套的,提交或者回滾以它們參與的相反順序進行。其中一個事務(wù)最為特別:如果存在問題,最重要的事務(wù)會回滾,即便是這問題是一個資源失敗。 同樣,testInsertWithCheckForDuplicates()測試方法展示了幕等式業(yè)務(wù)處理如何從部分失敗中保護系統(tǒng),此實現(xiàn)作為一個里層資源(otherDataSource)中業(yè)務(wù)運算防御檢測。
update首先嘗試和一個where子句執(zhí)行,不出意外,update中的數(shù)據(jù)會插入數(shù)據(jù)庫中。本例中的幕等式處理一個額外的花銷是sunny-day case中額外的查詢,這個額外的花銷在復(fù)雜的每個事務(wù)執(zhí)行多個查詢的業(yè)務(wù)處理中微乎其微。 其他選擇案例中的ChainedTransactionManager擁有簡潔優(yōu)勢,而且擴展優(yōu)化已做的很好。另一個方式是, 當?shù)诙€資源加入時,利用Spring的TransactionSychronization API給當前事務(wù) 注冊一個回調(diào)函數(shù),此方式在best-jms-db案例中,最大的特點是TransactionAwareConnectionFactory和一個 DataSourceTransactionManager的結(jié)合。利用TransactionSynchronizationManager,這個特殊的案例可以擴展并且泛化到包含non-JMS的資源中。這樣理論上有個優(yōu)勢,就是只有加入事務(wù)的資源得到支持,而非鏈上的 所有資源。然而配置依舊需要監(jiān)聽某個潛在的事務(wù)與之對應(yīng)的資源。 同樣,Spring工程師團隊考慮將最大努力一階段提交事務(wù)管理器特性作為Spring核心。你可以在JJRA issue中投票,如果你喜歡這種模式,希望Spring中顯示以及更加透明地支持此種模式。 非事務(wù)訪問模式非事務(wù)訪問模式需要一個特殊的業(yè)務(wù)處理,這樣才有意義。理想的狀態(tài)是有時,其中一些你需要訪問的資源邊緣化,一點都不需要事務(wù)。比如,或許你需要將一行數(shù)據(jù)插入一個 審核表中,此操作是獨立的,和業(yè)務(wù)事務(wù)是否成功無關(guān)。僅僅記錄試圖做了某事。更普遍的場景,人們高估了他們需要對其中一個資源做讀寫的頻次,事實上,只有 訪問就很好了。 否則,寫操作需要得到很好地控制,因此如果發(fā)生任何錯誤,寫操作可以被記錄下來或者忽略。 在以上的案例中資源恰當?shù)卦砣质聞?wù),但仍然有其自己的本地事務(wù),本地事務(wù)無需與其他發(fā)生的事情保持同步。如果你使用的是Spring,主要的事務(wù)由一個PlatformTransactionManager驅(qū)動, 邊緣資源或許是一個數(shù)據(jù)庫Connection,它來自一個不受事務(wù)管理器控制的DataSource。每一次訪問邊緣資源需要將缺省環(huán)境設(shè)為 autoCommit=true。updates對讀操作不可見,前者可以與其他非提交事務(wù)并發(fā)進行,但寫操作帶來的影響通常對其他操作來說是立即可見的。 這個模式需要更多精細地分析,以及更多自信去涉及業(yè)務(wù)處理,但它同最大努力一階段提交沒 什么區(qū)別。當任何事情出錯,一個通用的補償事務(wù)服務(wù)對多數(shù)項目來說太過龐大。不過簡單的用例所涉及的服務(wù),它是幕等式的僅僅執(zhí)行一個寫的操作,這種現(xiàn)象再 普通不過了。這些是非事務(wù)策略的理想場景。 Wing-and-a-Prayer:一種反模式最后一種模式是一種反模式,它出現(xiàn)這樣一個場景中,開發(fā)者不理解或者沒有意識到他們已經(jīng)存在一個分布式事務(wù)時。無需顯示的調(diào)用底層的資源事務(wù)API,你不確 定所有的資源是否在一個事務(wù)中。倘若用的是一個Spring事務(wù)管理器而非JtaTransactionManager,此管理器會將一個事務(wù)資源加入其中。這個事務(wù)管理器將會攔截Spring聲明事務(wù)管理特性的執(zhí)行方法,比如@Transactional;其他的資源不會注冊到相同的事務(wù)中。通常的結(jié)局 是任何事情都運轉(zhuǎn)正常,不過很快用戶會發(fā)現(xiàn)存在一個異常,其中一個資源沒有回滾。一個典型的錯誤導(dǎo)致的問題是利用一個 DataSourceTransactionManager以及一個利用Hibernate實現(xiàn)的倉庫。 該用哪個模式呢?我會通過分析已介紹過的模式其利弊,幫助大家做出取舍。第一步是分析你的系統(tǒng)是否需要分布式事務(wù)。一個必須但不充分條件是,存在不止一個事務(wù)資源的單一處理。充分條件是這些資源都在一個單獨的用例中,通常由系統(tǒng)架構(gòu)的service層調(diào)用來驅(qū)動。 如果你不認為這是分布式事務(wù),那最好采用Wing-and-a-Prayer模式,接著你會看見數(shù)據(jù)應(yīng)該回滾但沒有。或許你會看到這種影響從失敗發(fā)生直至其下游一直存在,而且很難追溯回去。Wing-and-a-Prayer的 使用也可能會開發(fā)人員所疏忽,他們認為受到了XA保障,其實并沒與配置底層資源加入到事務(wù)中。我曾經(jīng)做過一個這樣的項目,數(shù)據(jù)庫是其他人員搭建的,他們在 安裝數(shù)據(jù)庫的過程中關(guān)閉了XA支持。運行了個把月沒有任何問題,接著各種奇怪的失敗開始侵入業(yè)務(wù)處理中,需要花很長的時間去找出問題。 如果是一個包含異質(zhì)資源的簡單用例,你可以分析甚至做一些重構(gòu),那么非事務(wù)訪問模式或 許是個不錯的選擇,特別是其中一個幾乎是只讀資源,雙檢測確保寫操作。即便是失敗了,非事務(wù)資源中的數(shù)據(jù)在業(yè)務(wù)術(shù)語中必須有意義。審核、版本控制、甚至日 志信息能很好的切入到此目錄中,失敗變得相對很平?!?任何時間真實事務(wù)中的任何事情都可回滾,但你需確信這樣做不存在負面影響就好。 對系統(tǒng)而言,最大努力一階段提交需要通用的失敗保護機制,但有不存在2PC那么大的開銷,而且性能得到極大的提升。相對非事務(wù)資源,它的建立需要更多的技巧,但無需太多的分析, 通常應(yīng)用于更加通用的數(shù)據(jù)類型中。完成數(shù)據(jù)一致性的某些特性,需要保障業(yè)務(wù)處理對外層資源(”outer” resources:第一個提交的資源)而言是幕等式。消息驅(qū)動的數(shù)據(jù)庫更新就是一個完美的例子,并且在Spring中得到很好的支持。不常見的場景需要一些額外的框架代碼,這些代碼終究會成為Spring的一部分。 共享資源模式是一種特定的例子,通常涉及一個特定的類型和平臺兩個資源,比如,ActiveMQ和任何一個RDBMS或者OracleAQ與一個Oracle數(shù)據(jù)庫共存。這樣做最大的收益是相當?shù)撵`活以及出色的性能。 Full XA with 2PC是一種通用模式,在應(yīng)對多個異質(zhì)資源事務(wù) 失敗時提供很好的無憂保證。不利的是它的開銷很大,需要遵循特定的I/O協(xié)議和特定的平臺。有開源的JTA實現(xiàn),提供了一種擺脫應(yīng)用服務(wù)器的方式,但多數(shù) 開發(fā)人員依舊認為它們并非最好??梢源_信的是,人們花更多的時間去思考系統(tǒng)的事務(wù)界限,會更傾向于使用他們并不那么需要的JTA和XA。至少使用 Spring的開發(fā)人員,他們的業(yè)務(wù)邏輯無需知道事務(wù)如何被處理的,暫時無需考慮平臺選擇的問題。 原文鏈接: javaworld 翻譯: ImportNew.com - 喬永琪譯文鏈接: http://www./15812.html [ 轉(zhuǎn)載請保留原文出處、譯者和譯文鏈接。] |
|
來自: feimishiwo > 《spring》