JDBC分布式事務(wù)淺析
在沒有開始JDBC分布式事務(wù)前,先來回顧一下J2EE平臺的數(shù)據(jù)源的整體構(gòu)加:
在上面的介紹中,可能大家會過于限入理解如何實現(xiàn)ConnectionPoolDataSource和PooledConnection,而忘記了它的整體結(jié)構(gòu).為了幫助大家更快地理解,我從以下幾點進行總結(jié).
聲明:本文完全是作者根據(jù)SUN的文檔從實踐中總結(jié),沒有參考(事實上目前我還沒有找到這方面的參考)任何文章:
1.DataSource和ConnectionPoolDataSource的關(guān)系:
Sun的文檔中只對ConnectionPoolDataSource接口作了一般性規(guī)定,說明它是PooledConnection的工廠,即ConnectionPoolDataSource是傳統(tǒng)的連結(jié)池角色,它負責(zé)產(chǎn)生物理連結(jié)PooledConnection.而PooledConnection又是Connectio的工廠,一個PooledConnection對象負責(zé)產(chǎn)生多個Connection對象供應(yīng)用程序調(diào)用.
而DataSource是對上面兩個過程的包裝,在DataSource中不僅要實現(xiàn)傳統(tǒng)連結(jié)池ConnectionPoolDataSource來產(chǎn)生物理連結(jié)PooledConnection,還要實現(xiàn)通過每個PooledConnection工廠來產(chǎn)生Connection,最后DataSource通過公開方法返回給調(diào)用者的是經(jīng)過兩次工廠出來的Connection.如果我們先不考慮JDBC分布式事務(wù),只看下圖左邊,就是說工廠ConnectionPoolDataSource生成PooledConntion,二級工廠PooledConntion生產(chǎn)Connection,這兩個過程由DataSource在內(nèi)部包裝,只提供最后的產(chǎn)品Connection.
2.DataSource是服務(wù)端數(shù)據(jù)源,而傳統(tǒng)的連結(jié)池是客戶端數(shù)據(jù)源:
傳統(tǒng)的連結(jié)池要調(diào)用者生成這個連池的實例,完成初如化,這樣一個數(shù)據(jù)庫為了防止連結(jié)池的實例生成無限多個物理連結(jié),就要對保存物理連結(jié)的數(shù)據(jù)結(jié)構(gòu)進行靜態(tài)定義,否則,你在你的程序中生成一個連結(jié)池對象,它生成30個物理連結(jié),我又在我的程序中生成連結(jié)池實例,又生成30個物理連結(jié),那就無法控制了,所以保存這30個物理連結(jié)的數(shù)據(jù)結(jié)構(gòu)必須是靜態(tài)的.
而DataSource同一個對象初始化后,對象被綁定到j(luò)ndi服務(wù)器上,通過jdni得到的是它的代碼存根,其中只包含Connection,而物理連結(jié)是不可能序列化的,所以不會被重新生成,調(diào)用者通過Connection對象作為參數(shù)傳給服務(wù)端,由它來操作實際的物理連結(jié).
思考一下:如果不考慮性能問題,我是否可以把PooledConnction不再二次工廠化,只把PooledConntion作為Connection作為DataSource產(chǎn)品返回給調(diào)用者?
答案是不可以,因為物理連結(jié)不能序列化,也就是無法進行分布式引用.二次工廠化不僅解決了性能的問題,也同時解決了JDBC分布式事物調(diào)用的問題.
3.為什么說二次工廠化增加性能?
對于產(chǎn)生物理連結(jié),沒有什么區(qū)別,但物理連結(jié)本身并沒有滿負載工作,也就是一個物理Connection(TMD,我現(xiàn)在也不好說Connection還是PooledConnectio,以前的Connection就是DataSource中的PooledConnection)其實可以同時綁定更多的Statement,而如果它直接給調(diào)用者調(diào)用了,句柄就被調(diào)用者拿去了,在調(diào)用者沒有返回時別的Statement沒法和它進行”聯(lián)系”.而二次工廠的目的就是把多人的Statement通過”新的引用Connection”和物理連結(jié)綁定,使它更好地工作.
舉個例子,汽車這種東西,在目前的中國還是很昂貴的,作為客戶(調(diào)用者)我有幾件貨物要運,但一輛汽車(物理連結(jié))如果我一用,別人就不能用了.(傳統(tǒng)連結(jié)池和連結(jié)),盡管它還可以裝更多的貨物,現(xiàn)在汽車公司只能你一個車號(新的Connection),不給你實際的汽車,你只要把你的幾件東西只交給這個車號,而其他人也可能同時把幾件東西交給這個車號,最盡有更多的貨物因為使用同一車號而使那個物理汽車裝載了更多的貨物,當(dāng)然如果它滿了的話會產(chǎn)生另一輛車,如果生產(chǎn)的輛達到規(guī)定的數(shù)目你只好等等了,但這樣把多個客戶的貨物和同一車號關(guān)聯(lián)使汽車能更多地處理事務(wù),明顯地增加了性能.
理解了以上的結(jié)構(gòu),我們就不難理解javax.sql對分布式事務(wù)的支持,當(dāng)然,如果你對事務(wù)本身還不理解,那我就沒辦法讓你理解以下的知識,因為我不可能再停下來講什么是事務(wù).它是和JDBC相同級別的內(nèi)容,也許在別的地方我會再講.
從上面的結(jié)構(gòu)中右邊看到,在DataSource中,其實封裝了兩種工廠,這兩種工廠都是兩層次的,其實XADataSource的作用和ConnectioPooledDataSource一樣,都是產(chǎn)生物理連結(jié)的,只不過它產(chǎn)生支持分布式事務(wù)的物理連結(jié)XAConnectio而已,(以后記住,凡以XA命名的類都是支持JDBC分布式事務(wù)的標記.)我們看到,XAConnection中g(shù)etConnection()出來的連結(jié)和PooledConnection中g(shù)etConnection()出來的連結(jié)沒有區(qū)別,而Connection是DataSource的最終產(chǎn)品,這意味作什么?
這意味著支持分布式事務(wù)的過程由DataSource來做,你要操作的Connection和平時沒有兩樣,你只要聲明事務(wù)的開始和事務(wù)提交就行了!要使你的連結(jié)支持JDBC分布式事務(wù),你要在DataSource的配置中指明type是XADataSource就行了.然后申請一個一務(wù)(為了說明方便省略了
- try{}catch(){})
- UserTransaction ut = ...........;
- ut.begin();
- Connection con1 = .........;
- Connection con2 = .........;
- Connection con3 = .........;
- if(條件) ut.setRollbackOnly();
- con1.close();
- con2.close();
- con3.close();
考察一下,為什么XADataSource類型的物理工廠會產(chǎn)生的連結(jié)可以直接被事務(wù)管理呢?其實這就是封裝的好處了,在XADataSource產(chǎn)生XAConnection時,這個XAConnection實際是PooledConnection的子類,它擴展了一個getXAResource() 方法,事務(wù)通過這個方法把它加入到事務(wù)容器中進行管理.對于調(diào)用者來說,根本看不到事務(wù)是如果管理的,你只要聲明開始事務(wù),告訴容器我下面的操作要求事務(wù)參與了,最后告訴事務(wù)說到這兒可以提交或回滾了,別的都是黑箱操作,不要你來做.
當(dāng)然如果沒有分布式事務(wù)的需求,雖然XADataSource可以用于本地事務(wù),但它要做很多資源測試,是一種浪費.
最后要說明的是,既然你把操作交給事務(wù)來做,你就要對他放心,事務(wù)邊界由容器管理,你只在最后確定是提交還是回滾還是強行回滾setRollbackOnly()(強行回滾后不可以再提交).你不要在事務(wù)中調(diào)用某一連結(jié)的rollback,commit,也不能把Connection設(shè)為自動提交,一般來說當(dāng)你聲明為支持JDBC分布式事務(wù)的DataSource時,創(chuàng)建的連結(jié)默認都是關(guān)閉自動提交的,只是你自己不要打開它.
因為SUN的文檔只對DataSource接口作了一般規(guī)定,并沒有規(guī)定具體算法,所以我們在清楚上面的結(jié)構(gòu)后,可以實現(xiàn)不依賴容器的DataSource(其實只是它的思想.因為你寫出來的不依賴容器的DataSource)已經(jīng)不是這個意義上的DataSource了.它不能綁定到服務(wù)器上讓遠程引用,所以生成物理連結(jié)的工廠應(yīng)該是靜態(tài)的,而物理連結(jié)這種產(chǎn)品也應(yīng)該是靜態(tài)的.然后再生成多個引用連結(jié).但這好象沒有多大意義,因為純客戶端軟件一般來說不可能同時有上萬個客戶在線訪問的,根本用不著這么費事地實現(xiàn)連結(jié)池.
【編輯推薦】