EJB Transaction部分

Transaction部分

 

基本概念和詞彙:

n         Transaction object (or Transaction component): 是一個參與在事務當中的組件。如:Ejb 組件、.Net組件、Corba組件等。

n         Transaction manager: 負責管理Transaction objects的事 務操作。就像樂隊中的指揮一樣。

n         Resource:持久的數據源。如:數據庫、消息隊列等。

n         Resource manager: Resource的管理者,負責管理所有持久數據的 狀態。Resource manager的一個例子就是數據庫、消息隊列或其他存儲器的驅動,最流行的Resource manager的接口就是X/Open XA resource manager接口。很多數據庫驅動都支持這種接口,XA 事實上已經是Resource manager的工業標準。

n         ACID (atomicity, consistency, isolation, durability): 一個事務肯定會由數據庫給予四種擔保,他們是:原子性atomicity, 一致性consistency, 隔離性isolation, 持久性durability

Transaction models. 事務一般有兩種模型:扁平(flat)事務和嵌套(nested)事務。當前的Ejb規範只支持扁平事務而不支持嵌套事務。

n         扁平事務模型:就是將一系列操作視爲一個操作。事務開始之後,程序可以做任意多的操作,可以是持久化的操作也可以不是。這種模型的特點是:如果事務能夠正常結束則將所有操作持久化,否則所有操作都不會被持久化。

n         嵌套事務模型:將原子事務操作嵌套入其他事務操作中。一個小事務塊回滾不會導致整個事務回滾。而大的事務塊可以重試失敗了的小事務塊。你可以將嵌套事務模型想象爲一個樹狀模型,最大的事務塊是樹根,小的事務塊是樹葉,葉結點回滾不會影響他的父結點。

Ejb中的Transaction

n         EJBean會很自然的被事務化,他是做那種要求嚴格的系統的一個很好的選擇。

n         ejb中,Transaction會被抽象化、底層化,你的代碼不可能與Transaction managerResource manager交互。底層的事務控制被容器抽象化了,你的程序只要決定是否提交或回滾即可。

n         我們必須提供一些關鍵信息給容器,告訴他誰開始了事務、誰會提交或回滾事務、這些步驟何時發生。這被稱作“劃分事務邊界”。有三種劃分事務的方法:

1.         程序控制(Programmatic Transaction):事務都是由程序來控制,程序中顯式的調用begincommitrollback等方法。

2.         容器控制(Declarative Transaction):容器截取程序控制權然後自動調用begin開始事務,然後將控制權交還給Bean,這時bean可以做任何邏輯業務操作,如果程序遇 到問題可以給容器發送失敗信號,在Bean完成操作之後會將控制權交還給容器,這時容器決定是否commitrollback。你可以在Deploy descriptor配置文 件加入以下這句話來指出使用上述那種控制方式:

<transaction-type>Container</transaction-type>

這句話指出由容器來做事務控制,如果將Container替換爲Bean,則由程序來控制事務。

3.         客戶端控制(Client initiated transaction):可以在Bean的客戶端程序中控制事務,如:jspservletapplet或其他ejb等。但是要注意還是要在配置文件中指出被調用的Bean是 使用Programmatic Transaction還是Declarative Transaction

 

n         Transaction and Entity Bean

l         當你在transaction中調用Entity Bean時,容器首先調用Bean中的ejbLoad()方法從數據庫中得到數據,實際就是從數據庫得到數據鎖並且確定數據是否與緩衝池中的一致。然後調用 若干個業務邏輯方法,當事務被提交之後,ejbStore()方法被調用,他將所有更改過的數據寫入數據庫並且釋放鎖。

l         爲什麼Entity Bean只能使用Container-managed transaction?而Bean-managed transaction只能用於session beanmessage-driven bean?這是因爲:對於bean-managed transaction來說,你必須顯式的調用begin()commit()方法,在Entity bean中你可能會在ejbLoad()中開始事務,並且在ejbStore()中提交事務。但問題是,這兩個方法只能由容器調用,所以bean不能確定這兩個方法何時會被調用,也就是說你在ejbLoad()方法中開始了事務,或許這個事務永遠也不會被結束。而session beanmessage-driven bean中 可以隨意控制數據的操作,所以不存在這個問題。

l         Entity bean不會在每一個方法被調用的時候去讀寫數據庫,而是在一個事務之中。所以如果你的程序寫的不好,每一個函數調用的時候都開始一個事務,那麼每次調用這些函數的時候都會讀寫一次數據庫!解決的辦法是讓多個函數處於一個事 務當中,在配置文件中你可以配置這些。

n         程序控制、容器控制、客戶端控制這三種事務控制方法我們到底應該選擇哪一個呢?他們都各自有各自的優點:

l         程序控制:優點就是你可以在你的Bean中完全控制事務。比如,你可以在一個函數中運行多個小的事務;但是對於容器控制或客戶端控制事務的Entity Bean中的函數卻只能要麼 啓動一個事務要麼就一個都不能啓動。

l         容器控制:優點就是很簡單。可以減少代碼量並且不用更改代碼就可以調整事務。

l         客戶端控制:舉一個例子來說明這種控制方式的優點。假如一個沒有客戶端事務控制遠程用戶想要調用一個EJB,這個EJB有自己的事務控制。如果這個Bean的事務完成了,但是在操作結果返回 給客戶端的時候網絡或者服務器癱瘓了,這是java就會給客戶端拋出一個RMIRemoteException來告訴客戶端網絡出故障了。但是這樣的話客戶端不會知道Bean的事物是否成功結束,這是客戶端就要 寫代碼去知道事務是否成功,而這些代碼是非常繁瑣並且很容易出錯,因爲網絡的故障有可能客戶端永遠也連接不到服務器端了。客戶端控制的事務的好處就是可以解決這個問題。但是,如果客戶端遠離服務器端的時候,要少用這種控制方式,因爲如果距離太遠,那麼事務回滾的時候很有可能引起衝突。

n         容器控制的事務

l         我們必須提供一些事務屬性(Transaction attribution)來告訴容器怎樣控制事務。可以給每個Bean以不同的事務屬性。這些屬性定義在Deployment description中,而且你可以爲Bean定義屬性也可以爲Bean中的某個函數定義屬性,如果你對兩者都定義了事務屬性,則函數定義的屬性優先。

l         對於Message-Driven Bean來說,建議最好使用容器控制的事務。

l         以下是事務屬性值的解釋:

u       Required:必須使用事務,如果在這個Bean外面已經有了一個事務,那麼就加入到這個事務當中;否則就開始一個新的事務。

u       RequiresNew:無論外界是否有事務,都啓動一個新的事務。

u       Supports:如果外界已經有事務,則加入這個事務;否則,不會啓動新的事務。

u       Mandatory:規定Bean的函數被調用的時候必須已經啓動了一個事務,否則會拋出TransactionRequiredException

u       NotSupportedBean不會被事務控制。如果在調用Bean之前已經啓動了一個事務,那麼這個事務會被暫時掛起,直到Bean結束之後事務纔會繼續。

u       NeverBean不能進入事務,如果在一個事務中調用這個Bean的話會拋出RomoteException

l         注意:不同類型的Bean不一定支持上述所有類型的屬性值。如:Entiry Bean和帶有SessionSyncronizationStateful SessionBean不支持Never, NotSupported, Supports屬性;而Message-driven Bean不支持Never, Supports, RequiresNew, Mandatory屬 性。

n         Ejb程序控制的事務

l         程序控制的事務要比容器控制的事務更加靈活,但是比較繁瑣。而且必須要使用Java Transaction API(JTA)

l         Object Management Group(OMG)組織定義了一個標準Object Transaction Service(OTS)在事務的底層做了很多工作,使得我們的代碼就簡單多了,並且不用關心底層的操作。

l         Sun公司將OTSJava語言中分成了兩塊:Java Transaction Service(JTS)Java Transaction API(JTA)。其中JTS是給系統級的廠商使用的,它幫助我們做了很多底層的複雜的工作;而用戶只要使用JTA就可以了。

l         JTA分爲兩組接口:一組給X/Open XA resource manager使用;一組給用戶使用。用戶主要使用javax.transaction.UserTransaction接口。

l         UserTransaction接口共有六個方法:being(), commit(), rollback(), getStatus(), setRollBackOnly(), setTransactionTimeout()。使用Context.getUserTransaction()可以得到UserTransaction

l         如果想讓程序控制事務則必須在Deployment descriptor中將<transaction-type>置爲Bean

l         當我們在程序中啓動一個事務時,最好在同一個方法中結束這個事務,否則長時間打開事務會嚴重消耗系統資源。

l         如果一個函數處在一個已經被其他Bean創建好了的事務中,那麼這個函數怎樣才能銷燬這個事務呢?

u       在容器控制的事務中,不能通過拋出異常的手段來銷燬事務,因爲你拋出的異常有可能是你自己定義的異 常,容器無法知道你自己定義的異常是否嚴重到要銷燬事務的程度。所以因該使用Context.setRollBackOnly()方法來結束事務。

u       如果這個函數是一個普通的java object,則可以先找到JTA,然後調用setRollBackOnly()方法來結 束事務。

u       在一個事務中如果有十個Bean,其中第二個Bean發現錯誤並且作了setRollBackOnly()操作,那麼剩餘的幾個Bean就不能再做相同的操作,因爲這樣會大量的消耗資源。而應該得到當前事務的狀態,根據這個狀態來進行 操作。得到事務狀態的方法有兩種:如果是容器管理的事務使用getRollbackOnly()方法;如果是程序控制的事務使用getStatus()方法。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章