事務—EJB事務(CMT)

EJB3的事務與安全

EJB3的是事務也符合ACID,即原子性、一致性、隔離型、持久性。這些特性與數據庫事務一致,需要強調的是一致性,在事務開始前,系統是處於一種遵守業務規則和約束的一致狀態下,那麼在事務提交或回滾之後,系統也必須維持這種一致性狀態。在事務進行過程中不必處於不一致性狀態,事務在這裏就像一個沙箱(sand-box)。

在EJB中,事務也具有隔離級別的控制,但一般不用通過EJB容器來控制,而是在數據庫資源這一級別來進行控制。

要知道在EJB容器中,代碼層面的所有操作最終都是轉化爲兩級的數據庫操作,比如鎖定和解鎖數據庫中的某行或某張表。事務日誌來反映事務的變化,開始事務日誌代表事務的開始,應用日誌代表以提交該事務來結束,相反放棄日誌就代表回滾事務而結束。

資源管理器(Resource Manager)的概念是管理特定某種資源的事務的組件。這個概念不僅包括關係數據庫系統,也可以使消息服務器或其他業務系統。

如果只涉及一種單一資源的事務就稱爲local transaction本地事務,相反大多數企業應用都是需要涉及多種不同的資源。這時候就需要一種類型的組件來管理事務中多種資源,這個組件稱爲事務管理器(Transaction Manager),它在多個管理各自資源事務的資源管理之間進行協調和控制。

分佈式的事務管理是通過一種稱爲兩段式提交(two-phase commit)的機制來完成。現在最爲流行的分佈式事務協議是XA協議(XA Protocol),JavaEE就是通過該協議來完成分佈式應用中的事務管理。

事務管理

JavaEE中事務使用JTA(Java Transaction API,是建立在Java Transaction Service之上的服務),即javax.tranaction.UserTransaction接口,容器在後臺會自動管理大多數事務細節,EJB開發者只需控制開始和停止事務、建立事務邊界(transaction boundary)以及是否提交/回滾業務即可。

在EJB3中提供了兩種具體的事務方式,即容器管理的事務(Container-managed transaction,CMT)和bean管理的事務(Bean-managed transaction,BMT)。其中前者是使用聲明式地或通過部署描述符來管理事務;後者需要以顯式編碼的方式來管理。但需要注意的是在EJB3中,只有SessionBean和MessageDrivenBean才支持CMT和BMT,JPA中並不直接依賴CMT或BMT。但是當然,在任何JavaEE容器中都可透明得插入CMT或BMT的事務環境。

容器管理事務,即CMT。

容器管理的事務,顧名思義,容器來做“事務開始、事務提交或回滾”。容器在調用方法前開始JTA事務,接着會調用業務方法,最後根據調用中發生的情況去決定是提交事務還是回滾事務。使用CMT事務管理,只需關注@TransactionManagement和@TransactionAttribute註解,同時通過EJBContext的方法來回滾事務。

1.@TransactionMangement註解用於向容器標識該bean的事務管理是使用CMT還是BMT,是通過該標籤中的value屬性來指明TransactionManagementType的枚舉值。

2.@TransactionAttribute註解,儘管由容器爲我們來管理事務的各種細節,但是仍然需要通過該註解來告知容器如何去自動管理。

CMT對事務的管理可以在包裝bean的方法時開始,也可以從調用者的事務中進行join開始。

TransactionAttributeType有幾個枚舉值:

(1) REQUIRED:如果調用者沒有事務,容器則創建新事務;如果調用者具有事務,容器則連接join調用者事務。

(2) REQUIRED_NEW:如果調用者沒有事務,容器就創建新事務;如果調用者有事務,容器暫停原來事務,並創建新的事務。

(3) SUPPORTS:如果調用者沒有事務,容器就不創建事務;反之則join並使用調用者的事務。

(4) MANDATORY:如果調用者沒有事務,容器拋出javax.ejb.EJBTransactionRequiredException異常;反之則連接並使用調用者的事務。

(5) NOT_SUPPORTED:如果調用者沒有事務,容器便不使用事務調用方法;反之則暫停調用者事務以non-transactional的方式調用方法。

(6) NEVER:如果調用者沒有事務,容器直接調用方法;反正拋出javax.ejb.EJBException異常。

a. 對於第1種情況,適合的場景是從non-transactional的Web層調用bean方法,如果方法調用出現異常,那麼容器不僅會rollback整個事務,同時也會向調用者拋出javax.transaction.RollbackException異常,以通知調用者事務已被回滾了。

b. 第2種情況中,始終需要容器去創建新的事務,對於調用者原有的事物,容器就會暫停它,直到方法調用返回爲止就恢復原有事務。這樣的結果就是方法調用所創建的新事務無論成功與否,都不會對調用者原有的事務造成影響。

c. SUPPORT選項表示本質上容器將會按照調用者的事務情況來處理,通常的場景是用於一些只讀型的操作,比如檢索數據記錄等。

d. MANDATORY表示對容器對事務的強制性要求,如果調用者存在事務,容器就join並使用調用者事務;但如果調用者沒有事務環境,就會拋出EJBTransactionRequiredException異常。這種選項適合於如果方法調用失敗進行回滾時也保證調用者環境的失敗。

e. 對於NOT_SUPPORT,容器處理的本質是要求不能在事務環境下調用bean方法。如果調用者存在事務,容器會先暫停它,然後開始方法調用,在返回後恢復調用者的事務。

f. NEVER表明在CMT中,容器不能允許從事務性環境中調用bean方法,否則會拋出EJBException異常。

對於前面這六種TransactionAttributeType,MDB並不是全部都支持,它支持REQUIRED和NOT_SUPPORT兩種。這一點與MDB的特性有關:客戶端無法直接調用MDB,所以事務屬性中的SUPPORT、REQUIRED_NEW和MANDATORY就沒有意義。

CMT事務管理的真正機制

很重要的一點:CMT方法要求容器回滾事務並不是立即進行的,而是向容器設置回滾標識,在事務結束的時候,容器檢查該標誌,如果不需回滾則提交該事務,如果需要回滾則進行。

通過EJBContext或其子類:SessionContext和MessageDrivenContext的setRollbackOnly()方法,將回滾標誌位置爲true,當方法調用結束時,容器檢查該狀態以判斷是否提交事務或是回滾事務。

需要注意的一點是,本質上,使用EJBContext進行設置標誌位時,它是作爲底層事務的一個上層抽象代理。所以使用時,必須保證有底層事務存在,也就是說必須在REQUIRED,REQUIRED_NEW,MADATORY這三種事務屬性下使用!因爲這三種事務屬性都可以使容器保證底層事務的存在,即無論方法調用者是否存在事務環境,容器都會創建新事務。

與setRollbackOnly()方法對應的是getRollbackOnly()方法,該方法返回當前EJBContext中回滾標誌位的狀態。該方法在業務處理中十分有用,考慮這樣一個場景:

在進行一段非常長的資源密集型操作前如果前事務的前部分已經失敗,那就是在一個註定要回滾的事務上付出很多代價。所以在這類操作之前應該先check一下rollbackOnly是否已經置爲true。

此外,處理該標誌位狀態的代碼經常分佈在業務邏輯的catch塊中,如果catch了某種exception,則一邊記錄進log,一邊通過set方法置狀態位。在EJB3中,可以通過@ApplicationException註解使得“捕獲異常轉化爲事務回滾”變成透明的機制。

@AplicationException註解

@javax.ejb.ApplicationException該註解可以用來控制事務性輸出,將要拋出的異常類型在定義時加上該標籤,同時設置該標籤的rollback屬性,即@ApplicationException(rollback=true/false)。應用異常(ApplicationException)是希望調用者或客戶端處理的,一般認爲除了java.rmi.RemoteException和java.lang.RuntimeException之外都是應用異常。而從上述兩種異常繼承出的子類異常都被認爲是系統異常,這種異常不會傳遞給調用者或客戶端而是wrapped在EJBException中。

添加此註解的異常無論是checked exception還是unchecked exception(比如運行時異常),都會被認爲是應用異常(application exception),從而傳遞給方法調用者或客戶端。

默認情況下,所有checked exception或所有被註解爲應用異常的checked/unchecked exception,都不會以CMT的方式回滾,如果把rollback屬性設置爲true,則會通知容器失敗時進行事務回滾,並且是在把應用異常傳遞給調用者或客戶端之前進行的。

如果有未預料的unchecked exception,比如ArrayOutOfBoundsException或NullPointerException,容器仍然會回滾CMT事務,但是在這種情況下,容器會認爲bean處在了一種inconsistent的情況下,會進而銷燬bean實例,這是十分消耗資源的,所以you should never delibrately use system exceptions.

總結:

CMT使開發人員不必關心EJB事務中的大部分細節,當然同時CMT能提供對事務的控制級別也更少,這一點Bean管理的事務(BMT)更適合。

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