Java Transaction API 允許您操作應用程序中的分佈式事務(Distributed Transaction)。JTA 中有一組方法,它將傳統的 JDBC 調用封裝到了兩階段提交(Two-Phase-Commit)協議中。
在異構環境中,您通常會發現一個事務管理器(Transaction Manager),負責處理分佈式事務。(實際上,事務管理器可以完成大量的工作負載平衡。)因此,不僅存在到數據庫的直接連接,還有到事務管理器 (Transaction Manager)的連接。這就是 JTA 發揮作用的地方:JTA 是 Java 應用程序和事務管理器(Transaction Manager)之間的接口。下圖演示了一個包含分佈式事務的典型環境。
由於存在事務管理器(Transaction Manager),它通常包含在應用程序服務器(Application Server)中,就不再有兩層(Two-Tier)架構。傳統的客戶/服務器(Client/Server)架構已經由三層(Tree-Tier)架構 所取代,三層架構包含應用程序/客戶機、事務管理器(Transaction Manager)/應用程序服務器(Application Server)和數據庫服務器,而數據庫服務器一般稱作XA Resource。
- 包含 SQL 和 JTA 調用的 Java 應用程序。
- 管理分佈式事務的應用程序服務器(Application Server)。
- 參與分佈式事務的數據庫。
- Java 應用程序嚮應用程序服務器(Application Server)提交常規 SQL 語句和通用的 XA 調用。
- 應用程序所發送的消息由應用程序服務器(Application Server)進行處理,並使用 SQL 和數據庫供應商特定的 XA 調用發送給數據庫。
通常,應用程序服務器(Application Server)提供了應用程序可以使用的多種服務。在談到分佈式事務時,該服務就稱作XA Resource。當然,在應用程序可以使用 XA Resource 之前,首先要在應用程序服務器中註冊和配置 XA Resource。
現在,如果您計劃在應用程序中使用 JTA,就必須修改代碼,以便還可以與應用程序服務器(Application Server)進行通信。這包括一些附加的方法調用和指定的錯誤/異常處理
分佈式事務:
在談到 XA 規範之前,必須首先了解分佈式事務處理( Distributed Transaction Processing , DTP )的概念。 Transaction ,即事務,又稱之爲交易,指一個程序或程序段,在一個或多個資源如 數據庫 或文件上爲完成某些功能的執行過程的集合。
分佈式事務處理是指一個事務可能涉及多個數據庫操作,分佈式事務處理的關鍵是必須有一種方法可以知道事務在任何地方所做的所有動作,提交或回滾事務的決定必須產生統一的結果(全部提交或全部回滾)。
分佈式事務處理模型:
X/Open 組織(即現在的 Open Group )定義了分佈式事務處理模型。
X/Open DTP 模型( 1994 )包括:應用程序( AP )、事務管理器( TM )、資源管理器( RM )、通信資源管理器( CRM )四部分。一般,常見的事務管理器( TM )是交易中間件,常見的資源管理器( RM )是數據庫,常見的通信資源管理器( CRM )是消息中間件。
通常把一個數據庫內部的事務處理,如對多個表的操作,作爲本地事務看待。數據庫的事務處理對象是本地事務,而分佈式事務處理的對象是全局事務。
所謂全局事務,是指分佈式事務處理環境中,多個數據庫可能需要共同完成一個工作,這個工作即是一個全局事務,例如,一個事務中可能更新幾個不同的數據庫。對數據庫的操作發生在系統的各處,但必須全部被提交或回滾。此時一個數據庫對自己內部所做操作的提交不僅依賴本身操作是否成功,還要依賴與全局事務相關的其它數據庫的操作是否成功,如果任一數據庫的任一操作失敗,則參與此事務的所有數據庫所做的所有操作都必須回滾。
一般情況下,某一數據庫無法知道其它數據庫在做什麼,因此,在一個 DTP 環境中,交易中間件是必需的,由它通知和協調相關數據庫的提交或回滾。而一個數據庫只將其自己所做的操作(可恢復)影射到全局事務中。
XA 就是 X/Open DTP 定義的交易中間件與數據庫之間的接口規範(即接口函數)。交易中間件用它來通知數據庫事務的開始、結束以及提交、回滾等。XA 接口函數由數據庫廠商提供。
XA協議包括兩套函數,以xa_開頭的及以ax_開頭的。
以下的函數使事務管理器可以對資源管理器進行的操作:
1)xa_open,xa_close:建立和關閉與資源管理器的連接。
2)xa_start,xa_end:開始和結束一個本地事務。
3)xa_prepare,xa_commit,xa_rollback:預提交、提交和回滾一個本地事務。
4)xa_recover:回滾一個已進行預提交的事務。
5)ax_開頭的函數使資源管理器可以動態地在事務管理器中進行註冊,並可以對XID(TRANSACTION IDS)進行操作。
6)ax_reg,ax_unreg;允許一個資源管理器在一個TMS(TRANSACTION MANAGER SERVER)中動態註冊或撤消註冊。
JTA可以處理任何提供符合XA接口的資源。包括:JDBC連接,數據庫,JMS,商業對象等等。
XA 與兩階段提交協議(Two-Phase-Commit):
通常情況下,交易中間件與數據庫通過 XA 接口規範,使用兩階段提交來完成一個全局事務, XA 規範的基礎是兩階段提交協議。
第一階段:交易中間件請求所有相關數據庫準備提交(預提交)各自的事務分支,以確認是否所有相關數據庫都可以提交各自的事務分支。
當某一數據庫收到預提交後,如果可以提交屬於自己的事務分支,則將自己在該事務分支中所做的操作固定記錄下來,並給交易中間件一個同意提交的應答,此時數 據庫將不能再在該事務分支中加入任何操作,但此時數據庫並沒有真正提交該事務,數據庫對共享資源的操作還未釋放(處於上鎖狀態)。如果由於某種原因數據庫 無法提交屬於自己的事務分支,它將回滾自己的所有操作,釋放對共享資源上的鎖,並返回給交易中間件失敗應答。
第二階段:交易中間件審查所有數據庫返回的預提交結果,如所有數據庫都可以提交,交易中間件將要求所有數據庫做正式提交,這樣該全局事務被提交。而如果有任一數據庫預提交返回失敗,交易中間件將要求所有其它數據庫回滾其操作,這樣該全局事務被回滾。
以一個全局事務爲例, AP 首先通知交易中間件開始一個全局事務,交易中間件通過 XA 接口函數通知數據庫開始事務,然後 AP 可以對數據庫管理的資源進行操作,數據庫系統記錄事務對本地資源的所有操作。操作完成後交易中間件通過 XA 接口函數通知數據庫操作完成。交易中間件負責記錄 AP 操作過哪些數據庫(事務分支)。 AP 根據情況通知交易中間件提交該全局事務,交易中間件會通過 XA 接口函數要求各個數據庫做預提交,所有數據庫返回成功後要求各個數據庫做正式提交,此時一筆全局事務結束。
XA 規範對應用來說,最大好處在於事務的完整性由交易中間件和數據庫通過 XA 接口控制, AP 只需要關注與數據庫的應用邏輯的處理,而無需過多關心事務的完整性,應用設計開發會簡化很多。
具體來說,如果沒有交易中間件,應用系統需要在程序內部直接通知數據庫開始、結束和提交事務,當出現異常情況時必須由專門的程序對數據庫進行反向操作才能完成回滾。如果是有很多事務分支的全局事務,回滾時情況將變得異常複雜。而使用 XA 接口,則全局事務的提交是由交易中間件控制,應用程序只需通知交易中間件提交或回滾事務,就可以控制整個事務(可能涉及多個異地的數據庫)的全部提交或回滾,應用程序完全不用考慮衝正邏輯。
在一個涉及多個數據庫的全局事務中,爲保證全局事務的完整性,由交易中間件控制數據庫做兩階段提交是必要的。但 典型的兩階段提交,對數據庫來說事務從開始到結束(提交或回滾)時間相對較長,在事務處理期間數據庫使用的資源(如邏輯日誌、各種鎖),直到事務結束時才 會釋放。因此,使用典型的兩階段提交相對來說會佔用更多的資源,在網絡條件不是很好,如低速網、網絡顛簸頻繁,情況會更爲嚴重。
當一個全局事務只涉及一個數據庫時,有一種優化方式,即一階段提交。當 AP 通知交易中間件提交事務時,交易中間件直接要求數據庫提交事務,省去兩階段提交中的第一階段,可以縮短處理一個事務的時間,以提高事務處理的效率。作爲兩 階段提交的一種特例,與兩階段一樣,一階段提交也是標準的。
Two-phase commit
In an XA implementation, the transaction manager commits the distributed branches of a global transaction by using a two-phase commit protocol.
-
In phase one, the transaction manager directs each resource manager to prepare to commit, which is to verify and guarantee it can commit its respective branch of the global transaction. If a resource manager cannot commit its branch, the transaction manager rolls back the entire transaction in phase two.
-
In phase two, the transaction manager either directs each resource manager to commit its branch or, if a resource manager reported it was unable to commit in phase one, rolls back the global transaction.
Note the following optimizations:
-
If a global transaction is determined by the transaction manager to have involved only one branch, it skips phase one and commits the transaction in phase two.
-
If a global transaction branch is read-only, where it does not generate any transaction log records, the transaction manager commits the branch in phase one and skips phase two for that branch.
Note:
The transaction manager considers the global transaction committed if and only if all branches successfully commit.
兩階段提交詳細說明:
在分佈式系統中,事務往往包含有多個參與者的活動,單個參與者上的活動是能夠保證原子性的,而多個參與者之間原子性的保證則需要通過兩階段提交來實現,兩階段提交是分佈式事務實現的關鍵。
很明顯,兩階段提交保證了分佈式事務的原子性,這些子事務要麼都做,要麼都不做。而數據庫的一致性是由數據庫的完整性約束實現的,持久性則是通過 commit日誌來實現的,不是由兩階段提交來保證的。至於兩階段提交如何保證隔離性,可以參考Large-scale Incremental Processing Using Distributed Transactions and Notifications中兩階段提交的具體實現。
兩階段提交的過程涉及到協調者和參與者。協調者可以看做成事務的發起者,同時也是事務的一個參與者。對於一個分佈式事務來說,一個事務是涉及到多個參與者的。具體的兩階段提交的過程如下:
第一階段:
首先,協調者在自身節點的日誌中寫入一條的日誌記錄,然後所有參與者發送消息prepare T,詢問這些參與者(包括自身),是否能夠提交這個事務;
參與者在接受到這個prepare T 消息以後,會根據自身的情況,進行事務的預處理,如果參與者能夠提交該事務,則會將日誌寫入磁盤,並返回給協調者一個ready T信息,同時自身進入預提交狀態狀態;如果不能提交該事務,則記錄日誌,並返回一個not commit T信息給協調者,同時撤銷在自身上所做的數據庫改;
參與者能夠推遲發送響應的時間,但最終還是需要發送的。
第二階段:
協調者會收集所有參與者的意見,如果收到參與者發來的not commit T信息,則標識着該事務不能提交,協調者會將Abort T 記錄到日誌中,並向所有參與者發送一個Abort T 信息,讓所有參與者撤銷在自身上所有的預操作;
如果協調者收到所有參與者發來prepare T(ready T)信息,那麼協調者會將Commit T日誌寫入磁盤,並向所有參與者發送一個Commit T信息,提交該事務。若協調者遲遲未收到某個參與者發來的信息,則認爲該參與者發送了一個VOTE_ABORT信息,從而取消該事務的執行。
參與者接收到協調者發來的Abort T信息以後,參與者會終止提交,並將Abort T 記錄到日誌中;如果參與者收到的是Commit T信息,則會將事務進行提交,並寫入記錄。
一般情況下,兩階段提交機制都能較好的運行,當在事務進行過程中,有參與者宕機時,他重啓以後,可以通過詢問其他參與者或者協調者,從而知道這個事務到底提交了沒有。當然,這一切的前提都是各個參與者在進行每一步操作時,都會事先寫入日誌。
唯一一個兩階段提交不能解決的困境是:當協調者在發出commit T消息後宕機了,而唯一收到這條命令的一個參與者也宕機了,這個時候這個事務就處於一個未知的狀態,沒有人知道這個事務到底是提交了還是未提交,從而需要 數據庫管理員的介入,防止數據庫進入一個不一致的狀態。當然,如果有一個前提是:所有節點或者網絡的異常最終都會恢復,那麼這個問題就不存在了,協調者和 參與者最終會重啓,其他節點也最終也會收到commit T的信息。
數據庫日誌保證了事務執行的原子性和持久性,日誌類型可以分爲redo log,undo log,undo/redo log。關於這幾種日誌形式的具體介紹,可以參照:http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog