完全是自己學習的心得,還請前輩們指點。
EJB3的事務與安全
EJB3的是事務也符合ACID,即原子性、一致性、隔離型、持久性。這些特性與數(shù)據(jù)庫事務一致,需要強調(diào)的是一致性,在事務開始前,系統(tǒng)是處于一種遵守業(yè)務規(guī)則和約束的一致狀態(tài)下,那么在事務提交或回滾之后,系統(tǒng)也必須維持這種一致性狀態(tài)。在事務進行過程中不必處于不一致性狀態(tài),事務在這里就像一個沙箱(sand-box)。
在EJB中,事務也具有隔離級別的控制,但一般不用通過EJB容器來控制,而是在數(shù)據(jù)庫資源這一級別來進行控制。
要知道在EJB容器中,代碼層面的所有操作最終都是轉化為兩級的數(shù)據(jù)庫操作,比如鎖定和解鎖數(shù)據(jù)庫中的某行或某張表。事務日志來反映事務的變化,開始事務日志代表事務的開始,應用日志代表以提交該事務來結束,相反放棄日志就代表回滾事務而結束。
資源管理器(Resource Manager)的概念是管理特定某種資源的事務的組件。這個概念不僅包括關系數(shù)據(jù)庫系統(tǒng),也可以使消息服務器或其他業(yè)務系統(tǒng)。
如果只涉及一種單一資源的事務就稱為local transaction本地事務,相反大多數(shù)企業(yè)應用都是需要涉及多種不同的資源。這時候就需要一種類型的組件來管理事務中多種資源,這個組件稱為事務管理器(Transaction Manager),它在多個管理各自資源事務的資源管理之間進行協(xié)調(diào)和控制。
分布式的事務管理是通過一種稱為兩段式提交(two-phase commit)的機制來完成。現(xiàn)在最為流行的分布式事務協(xié)議是XA協(xié)議(XA Protocol),JavaEE就是通過該協(xié)議來完成分布式應用中的事務管理。
事務管理
JavaEE中事務使用JTA(Java Transaction API,是建立在Java Transaction Service之上的服務),即javax.tranaction.UserTransaction接口,容器在后臺會自動管理大多數(shù)事務細節(jié),EJB開發(fā)者只需控制開始和停止事務、建立事務邊界(transaction boundary)以及是否提交/回滾業(yè)務即可。
在EJB3中提供了兩種具體的事務方式,即容器管理的事務(Container-managed transaction,CMT)和bean管理的事務(Bean-managed transaction,BMT)。其中前者是使用聲明式地或通過部署描述符來管理事務;后者需要以顯式編碼的方式來管理。但需要注意的是在EJB3中,只有SessionBean和MessageDrivenBean才支持CMT和BMT,JPA中并不直接依賴CMT或BMT。但是當然,在任何JavaEE容器中都可透明得插入CMT或BMT的事務環(huán)境。
EJB3中管理事務最簡單靈活的方式是采用容器管理事務,即CMT。
容器管理的事務,顧名思義,容器來做“事務開始、事務提交或回滾”。容器在調(diào)用方法前開始JTA事務,接著會調(diào)用業(yè)務方法,最后根據(jù)調(diào)用中發(fā)生的情況去決定是提交事務還是回滾事務。使用CMT事務管理,只需關注@TransactionManagement和@TransactionAttribute注解,同時通過EJBContext的方法來回滾事務。
1.@TransactionMangement注解用于向容器標識該bean的事務管理是使用CMT還是BMT,是通過該標簽中的value屬性來指明TransactionManagementType的枚舉值。
2.@TransactionAttribute注解,盡管由容器為我們來管理事務的各種細節(jié),但是仍然需要通過該注解來告知容器如何去自動管理。
CMT對事務的管理可以在包裝bean的方法時開始,也可以從調(diào)用者的事務中進行join開始。
TransactionAttributeType有幾個枚舉值:
(1) REQUIRED:如果調(diào)用者沒有事務,容器則創(chuàng)建新事務;如果調(diào)用者具有事務,容器則連接join調(diào)用者事務。
(2) REQUIRED_NEW:如果調(diào)用者沒有事務,容器就創(chuàng)建新事務;如果調(diào)用者有事務,容器暫停原來事務,并創(chuàng)建新的事務。
(3) SUPPORTS:如果調(diào)用者沒有事務,容器就不創(chuàng)建事務;反之則join并使用調(diào)用者的事務。
(4) MANDATORY:如果調(diào)用者沒有事務,容器拋出javax.ejb.EJBTransactionRequiredException異常;反之則連接并使用調(diào)用者的事務。
(5) NOT_SUPPORTED:如果調(diào)用者沒有事務,容器便不使用事務調(diào)用方法;反之則暫停調(diào)用者事務以non-transactional的方式調(diào)用方法。
(6) NEVER:如果調(diào)用者沒有事務,容器直接調(diào)用方法;反正拋出javax.ejb.EJBException異常。
a. 對于第1種情況,適合的場景是從non-transactional的Web層調(diào)用bean方法,如果方法調(diào)用出現(xiàn)異常,那么容器不僅會rollback整個事務,同時也會向調(diào)用者拋出javax.transaction.RollbackException異常,以通知調(diào)用者事務已被回滾了。
b. 第2種情況中,始終需要容器去創(chuàng)建新的事務,對于調(diào)用者原有的事物,容器就會暫停它,直到方法調(diào)用返回為止就恢復原有事務。這樣的結果就是方法調(diào)用所創(chuàng)建的新事務無論成功與否,都不會對調(diào)用者原有的事務造成影響。
c. SUPPORT選項表示本質(zhì)上容器將會按照調(diào)用者的事務情況來處理,通常的場景是用于一些只讀型的操作,比如檢索數(shù)據(jù)記錄等。
d. MANDATORY表示對容器對事務的強制性要求,如果調(diào)用者存在事務,容器就join并使用調(diào)用者事務;但如果調(diào)用者沒有事務環(huán)境,就會拋出EJBTransactionRequiredException異常。這種選項適合于如果方法調(diào)用失敗進行回滾時也保證調(diào)用者環(huán)境的失敗。
e. 對于NOT_SUPPORT,容器處理的本質(zhì)是要求不能在事務環(huán)境下調(diào)用bean方法。如果調(diào)用者存在事務,容器會先暫停它,然后開始方法調(diào)用,在返回后恢復調(diào)用者的事務。
f. NEVER表明在CMT中,容器不能允許從事務性環(huán)境中調(diào)用bean方法,否則會拋出EJBException異常。
對于前面這六種TransactionAttributeType,MDB并不是全部都支持,它支持REQUIRED和NOT_SUPPORT兩種。這一點與MDB的特性有關:客戶端無法直接調(diào)用MDB,所以事務屬性中的SUPPORT、REQUIRED_NEW和MANDATORY就沒有意義。
CMT事務管理的真正機制
很重要的一點:CMT方法要求容器回滾事務并不是立即進行的,而是向容器設置回滾標識,在事務結束的時候,容器檢查該標志,如果不需回滾則提交該事務,如果需要回滾則進行。
通過EJBContext或其子類:SessionContext和MessageDrivenContext的setRollbackOnly()方法,將回滾標志位置為true,當方法調(diào)用結束時,容器檢查該狀態(tài)以判斷是否提交事務或是回滾事務。
需要注意的一點是,本質(zhì)上,使用EJBContext進行設置標志位時,它是作為底層事務的一個上層抽象代理。所以使用時,必須保證有底層事務存在,也就是說必須在REQUIRED,REQUIRED_NEW,MADATORY這三種事務屬性下使用!因為這三種事務屬性都可以使容器保證底層事務的存在,即無論方法調(diào)用者是否存在事務環(huán)境,容器都會創(chuàng)建新事務。
與setRollbackOnly()方法對應的是getRollbackOnly()方法,該方法返回當前EJBContext中回滾標志位的狀態(tài)。該方法在業(yè)務處理中十分有用,考慮這樣一個場景:
在進行一段非常長的資源密集型操作前如果前事務的前部分已經(jīng)失敗,那就是在一個注定要回滾的事務上付出很多代價。所以在這類操作之前應該先check一下rollbackOnly是否已經(jīng)置為true。
此外,處理該標志位狀態(tài)的代碼經(jīng)常分布在業(yè)務邏輯的catch塊中,如果catch了某種exception,則一邊記錄進log,一邊通過set方法置狀態(tài)位。在EJB3中,可以通過@ApplicationException注解使得“捕獲異常轉化為事務回滾”變成透明的機制。
@AplicationException注解
@javax.ejb.ApplicationException該注解可以用來控制事務性輸出,將要拋出的異常類型在定義時加上該標簽,同時設置該標簽的rollback屬性,即@ApplicationException(rollback=true/false)。應用異常(ApplicationException)是希望調(diào)用者或客戶端處理的,一般認為除了java.rmi.RemoteException和java.lang.RuntimeException之外都是應用異常。而從上述兩種異常繼承出的子類異常都被認為是系統(tǒng)異常,這種異常不會傳遞給調(diào)用者或客戶端而是wrapped在EJBException中。
添加此注解的異常無論是checked exception還是unchecked exception(比如運行時異常),都會被認為是應用異常(application exception),從而傳遞給方法調(diào)用者或客戶端。
默認情況下,所有checked exception或所有被注解為應用異常的checked/unchecked exception,都不會以CMT的方式回滾,如果把rollback屬性設置為true,則會通知容器失敗時進行事務回滾,并且是在把應用異常傳遞給調(diào)用者或客戶端之前進行的。
CMT使開發(fā)人員不必關心EJB事務中的大部分細節(jié),當然同時CMT能提供對事務的控制級別也更少,這一點Bean管理的事務(BMT)更適合。
posted @ 2009-06-06 21:11 J@mes 閱讀(924) | 評論 (0) | 編輯 收藏