#0 系列目錄#java
#1 X/Open DTP# DTP全稱是Distributed Transaction Process,即分佈式事務模型。以前咱們接觸的事務都是針對單個數據庫的操做,若是涉及多個數據庫的操做,還想保證原子性,這就須要使用分佈式事務了。而X/Open DTP就是一種分佈式事務處理模型。mysql
##1.1 X/Open DTP模型## web
上面主要涉及了三個對象:sql
他們三者的關係:數據庫
##1.2 兩階段提交## 全稱是The two-phase commit protocol,簡稱2PC。tomcat
當須要協調多個資源管理器進行分佈式事務的時候,就須要使用到兩階段提交協議,以下圖所示:服務器
第一個階段:事務管理器經過XA協議,向資源管理器發送prepare命令,詢問他們預提交是否成功,每一個資源管理器給出本身的響應,預提交成功或者失敗。框架
第二個階段:根據第一個階段的資源管理器的回覆狀況,若是所有表示預提交成功,則事務管理器向全部的資源管理器發送最終的提交命令。若是有一個資源管理器回覆預提交失敗,則事務管理器向全部的資源管理器發送回滾命令,所有進行回滾。分佈式
經過這樣的兩階段提交協議,便可完成了分佈式事務的功能。這樣的協議的正是基於了事務管理器和資源管理器的雙向通訊能力,而這在以前的本地事務中,如jdbc事務中,咱們只能經過Connection向數據庫傳遞命令,不能從數據庫獲取事務的一些執行信息,這種狀況是單向的。性能
然而仍是存在一些問題的:
兩階段提交協議是阻塞式協議,因此事務管理器必須等待每個資源管理器發送回覆以後,才能進行下一步操做。一旦資源管理器掛掉,事務管理器則收不到響應,就會形成事務管理器一直等待。這時候就必須引入超時機制,一旦超過某個時間尚未回覆,則認爲失敗,回滾全部操做,這些都是很是耗性能的。
一旦事務管理器掛掉,則資源管理器則一直等待事務管理器的命令。這時候可能就須要使用備份的事務管理器來接替原來的事務管理器的工做。
#2 JTA接口定義# 上述接口規範不是針對某種語言的,java是如何來落實上述規範的呢?這就是JTA的內容了。先來預覽下JTA的包結構:
主要2個大包的內容:(1)javax.transaction;(2)javax.transaction.xa;
##2.1 AP、TM、RM三大對象##
AP:咱們的應用程序。
TM:即javax.transaction.TransactionManager 事務管理器。
RM:即javax.transaction.xa.XAResource 我稱之爲與資源管理器的一個通訊表明,咱們經過XAResource接口方法和資源管理器進行通訊。
begin():建立一個新的事務並關聯到當前線程
Transaction getTransaction():獲取與當前線程關聯的事務
commit():提交與當前線程關聯的事務
rollback():回滾與當前線程關聯的事務
等等
定義了一些經常使用的事務操做,這裏操做的事務的定義爲javax.transaction.Transaction,接口以下所示:
commit():提交事務
rollback():回滾事務
enlistResource(XAResource xaRes):把給定的XAResource(資源管理器的一個通訊表明)加入當前事務中來,一個分佈式事務會涉及與多個資源管理器交互,該操做就是把某個資源管理器的通訊表明歸入當前事務中來
delistResource(XAResource xaRes, int flag):把給定的XAResource(資源管理器的一個通訊表明)從當前事務中去除
咱們看到有一個Xid接口:X/Open組織規定了,對於每一個分佈式事務,都有一個對應的惟一標示。這個惟一標示在java中就是Xid接口。
接下來看下XAResource的其餘方法:
start(Xid xid, int flags)和end(Xid xid, int flags)用於告知資源管理器的事務的邊界,即在這兩個方法之間的sql等操做纔會歸入xid對應的分佈式事務中
prepare(Xid xid):則就是上述圖片中的第一個階段,針對xid對應的分佈式事務,向資源管理器發送預提交命令
rollback(Xid xid)、commit(Xid xid, boolean onePhase) 若是全部資源管理器都回復OK,則向全部資源管理器發送commit提交命令,不然發送rollback回滾命令
下面看一個簡單模擬兩階段提交的例子,加深對上面的方法的理解:
xaRes1.start(xid, XAResource.TMNOFLAGS); stmt1.executeUpdate("insert into test_table1 values (100)"); xaRes1.end(xid, XAResource.TMSUCCESS); stmt1.executeUpdate("insert into test_table1 values (99)"); xaRes2.start(xid, XAResource.TMNOFLAGS); stmt2.executeUpdate("insert into test_table2 values (100)"); xaRes2.end(xid, XAResource.TMSUCCESS); ret1 = xaRes1.prepare(xid); ret2 = xaRes2.prepare(xid); if (ret1 == XAResource.XA_OK && ret2 == XAResource.XA_OK) { xaRes1.commit(xid, false); xaRes2.commit(xid, false); }else{ xaRes1.rollback(xid); xaRes2.rollback(xid); }
過程說明:
首先使用start、end來告知資源管理器分佈式事務的邊界,上述stmt1.executeUpdate("insert into test_table1 values (99)");沒有在start、end範圍以內,則不會劃入分佈式事務的管轄中,而是做爲了通常的本地事務。
而後遍歷每一個資源管理器的通訊表明,使他們詢問資源管理器預提交的狀況
若是所有OK則所有提交,不然所有回滾
更多的例子,能夠參考這裏JAVA分佈式事務原理及應用。
##2.2 UserTransaction接口## UserTransaction接口是給開發人員使用的事務接口,屏蔽了底層的實現細節,經過該接口就能夠操做一個分佈式事務。該接口的實現一般是委託給TM即事務管理器來完成。接口內容以下:
能夠看到,UserTransaction的這些方法在TM即事務管理器中都有對應的方法。
##2.3 JTA中涉及的角色##
更多的支持分佈式的數據庫驅動能夠看下這裏XA Drivers。
##2.4 JTS## JTS是什麼呢?它和JTA是什麼關係呢?
這個我也是沒弄清楚,能夠參考這裏的說法,若是以爲不對,自行去深刻研究下,原文在這裏JTA、JTS各司其職,共職分佈式事務。
JTS也定義了一套規範,它約定了各個程序角色之間如何傳遞事務上下文,它源自CORBA 的OTS規範,基於IIOP(一種軟件交互協議)。不要認爲JTS是JTA的實現,JTA其實就定義了一個空架子,告訴JTA的實現者應該怎樣作怎樣作,可是具體到作的時候JTS就來插一手了。由於JTA約定的這些角色要進行事務上下文的交互啊,JTS約定了應該怎樣去進行交互。
##2.5 疑問解答##
不是,可使用第三方框架如jotm、Atomikos來模擬XA協議。
不是。
jboss是支持的,因此咱們能夠直接使用jboss本身實現的UserTransaction來實現分佈式事務(使用JNDI方式,這時候要求數據庫驅動支持XA協議),能夠不須要像jotm、Atomikos等第三方框架。
tomcat就是不支持的,可是咱們可使用第三方框架來實現,如jotm、Atomikos。