top
Loading...
EnterpriseJavaBeans導論七
b>自管理的事務

如果聲明一個bean的事務控制為TX_BEAN_MANAGED,則這個bean可以訪問事務服務。當事務控制應用于單個的方法時這個控制只能應用于整個的bean. bean訪問事務服務的能力不能只對某個方法起作用。因此一個方法聲明事務控制為TX_BEAN_MANAGED,而另一個方法聲明為其它不同的事務控制是錯誤的。廠商的安裝工具應該能檢測到并報告這個錯誤。Bean分別通過初始化時setSessionContext()或setEntityContext()方法的參數 SessionContext或EntityContext來訪問事務服務。這些接口都是EJBContext的子類。

EJBContext的定義如下:

Public interface javax.ejb.EJBContext {
public Identity getCallerIdentity();
public boolean isCallerInRole(Identity other);
public EJBHome getEJBHome();
public Properties getEnvironment();
public UserTransaction getUserTransaction() throwsIllegalStateException;
public boolean getRollbackOnly();
public void set RollbackOnly();
}


一旦bean獲得了一個UserTransaction的引用,就可以用這個引用管理自己的事務。有狀態的會話bean的方法可以創建一個事務,而且不用終止事務就可以返回。如果還有線程調用bean的方法,容器檢測是否有bean創建的活動的事務,如果被調用的事務是同一個事務,容器會允許該線程重新進入這個bean.如果bean在事務中且執行不同事務上下文的線程試圖進入bean,容器會阻塞這個線程直到bean的事務終止。如果線程試圖進 入事務時bean不在事務中,線程會執行一個自己的事務,容器會掛起線程當前的事務以允許線程進入。一旦線程離開方法就會恢復線程以前的事務,容器不會終止任何方法創建的事務。

對于無狀態會話bean和實體bean,當事務活動時bean的方法不允許返回。容器會為此拋出一個例外。

Leaving a tranaction active across method calls is stateful,and is not allowed for stateless session beans.Fro similar reasons,entity beans are also not allowed to maintain an open transaction state across method calls when the bean has declared the TX_BEAN_MANAGED transaction control.


會話同步接口

有狀態和無狀態的會話bean都可以訪問數據庫,并且參與一個事務。為了讓bean在事務中執行它的任務 ean開發者可以實現在bean中實現 javax.ejb.SessionSynchronization接口。容器能自動檢測這個接口,容器會使用這個接口中的方法以使bean得到事務的狀態信息。實體bean不支持這個接口。因為實體bean are implicitly transaction aware,所以容器使用不同的方法控制一個事務中的實體 bean.

SessionSynchronization接口定義如下:

public interface javax.ejb.SessionSynchronization {
public void afterBegin() throws RemoteException;
public void beforeCompletion() throws RemoteException;
public void afterCompletion(boolean yn) throws RemoteException;
}

實際上一個事務不屬于一個特殊的bean的實例。一個客戶端或容器中執行的線程創建一個事務,在執行bean中的代碼時執行該事務。如果一個有事務上下文的線程將要進入一個會話bean,容器首先調用它的afterBegin()方法。Bean可以記錄所有的商業方法運行在事務中,隨后執行事務操作。如果一個操作的內部標志顯示這個線程在事務外運行,則會拒絕執行事務操作的請求。直到調用afterCompletion()方法,bean會繼續認為商業方法的調用都在事務中執行。Bean將推斷性地清除內部標志,以表示隨后到來的事務請求將被拒絕。

如果一個事務上下文的線程試圖進入一個已經是另一個事務的一部分的Bean時, .Container將封鎖入口,直到前一個事務提交或回滾,并且afterCompletion()方法被調用,此時,允許Bean 恢復它的狀態。Container負責提供這些行為。當Container發現它將要提交一個事務時,將在這個事務的所有的session Bean上調用beforeCompletion()方法。這就給Bean足夠的機會來結束事務的操作,如在提交前將數據寫入數據庫。反之,當Container 發現,將要回滾一個事務撕,BeforeCompletion()方法將不會被調用,因為將一個將被回滾的事務所產生的數據寫入數據庫是沒有意義 的。

AfterCompletion()是在一個事務即將提交或回滾時被調用,來通知Bean事務操作的最終結果。Bean可以用這個信息來修正自己的內部狀態,但它不能用這個信息來維持任何它將要保存的事務。盡管session Bean可以創建,提交和回滾它自己的事務,但通常不推薦這樣做。

SessionSynchronization接口不提供整合外部和內部事務的能力。如果一個session bean實現了這個接口,則意味著它在方法調用之間要保持事務的狀態。特別地,這也暗示在afterBegin()和afterCompletion()調用之間bean是處于一個事務中。這樣,如果一個bean實現了SessionSynchronization接口并且在裝配符中聲明是無狀態的就是一個錯誤。廠商提供的安裝工具應該可以捕捉到并報告這個錯誤。無狀態的session bean可以加入一個事務,但它們不能實現這個接口。事務可以是TX_BEAN_MANAGED,或者container可以在方法入口和從方法的返回上來開始和提交這個事務。Container不可允許在一個現存的事務中有一個線程進入方法,因為無狀態的Bean的方法將無法知道正在運行的線程是否正在一個事務中。

解決這個問題的一個方法是使container掛起現存的事務,強迫方法總是認為線程沒有在一個事務性的上下文中運行。有狀態的Bran可以不實現這個接口而介入事務。但是,裝配符必須要認真地配置以使得商務方法總能在正確的事務狀態中運行。Bean自己沒有通過這個接口來獲得自己的事務的狀態的權利。

加入事務

EJBContext接口在前面的一節中已經介紹了。其中有兩個方法:

public boolean getRollbackOnly();
public void setRoolbackOnly();

這些方法可以有任何bean來使用,而不僅僅是那些聲明了其事務控制為bean-managed的bean。事實上,那些處理自己的事務的bean將不會用到這些方法,因為這些方法不是用來和外界的事務管理器進行交流事務狀態的。

當一個bean調用了setRollBackOnly()方法時,它是在向事務管理器詢問何時結束將要回滾的當前事務。它將給它所參與的事務的結果一個選票。這些方法還存在于UserTransaction接口中,但由于大多數的bean都不訪問這個接口,這些方法必須直接地在EJBContext中提供給bean。注意這個方法并不引發回滾操作,它只是簡單地設置標志,表示事務在結束時應該回滾。不象JavaBan屬性設置方法,這個方法不以boolean值作為參數。這個方法是特意設計成這樣,以使得一個bean不能夠改變另一個bean的回滾請求。一個bean也許希望使用getRoolBackOnly()方法,來檢查當前的事務的狀態。如果另一個bean已經標志這個事務為rollback,則正在調用的bean可以推測到并決定不能執行那些在、強制性達到操作,如數據庫更新,而這些操作很有可能在事務結束時被反轉過來。

客戶劃分的事務

盡管一個JEB廠商所必須的,大服務器廠商也許決定提供一個類,使得用戶可以直接訪問事務管理器。當需要在同一個上下文中在兩個不同的服務器上調用bean時,用戶也許會希望這樣做。當然,每個bean的裝配符可以允許這樣的行為。用戶可以創建一個事務,然后在兩個不同server上的兩個不同的bean上調用商務方法,而將事務的上下文也作為調用的一部分進行傳遞。一旦調用結束,用戶將推測地結束事務。有container廠商產生的stub和skeleton將支持事務上下文的隱式傳遞。

這里是一個可能的例子:

Current current = new Current();
Current.setServiceProvider(txMgrURL);
Current.create();
Current.begin();
Current.doSomeWork();
RemRef1.doSomeWork();
RemRef2.doMoreWork();
Current.commit();

數據庫操作的事務管理

bean當然希望使用JDBC來建立到數據庫的連接,并在其上進行操作。但是,為了符合EJB這種container管理事務的模式,連接不能使用自動提交特性,并且不應該在連接上試圖提交或回滾。

Container的角色是決定在這個事務中執行的所有行為應該提交還是回滾。這里提這樣一個問題很好:container如何看到并管理由bean方法內部創建的數據庫連接。盡管在規范中沒有明確地提到,EJB將只能使用JDBC驅動,而JDBC也正是用來和EJB配合使用的。在數據庫連接的創建時,驅動程序透明地將連接注冊到正在執行的線程的當前事務中。之后當container決定結束事務時,數據庫連接將自動地結束它。用OTS的術語說,數據庫連接是不可恢復的資源,有事務服務在container的協助下,隱式地管理。盡管可以在這種情況下使用非事務感知的JDBC Driver,但開發者必須清楚任何在數據庫連接上所做的操作都不屬于bean的事務,開發者還必須確保在從方法返回之前結束數據庫連接事務。試圖使用SessionSynchronization接口來合并數據庫連接事務和bean本身的事務是不可靠的,是不應該作的。

分布事務的支持

一個分布事務在下面的情況下是需要的:
. 一個用戶使用用戶劃分的在多個server上的多個bean中創建和調用方法的事務。
. 一個在其他的server上調用其他EJB的方法的bean的方法。

對于這些工作廠商必須為EJBObject生成stub和skeleton來隱式地獲得當前事務的上下文,同時將其通過方法調用傳到遠程bean。當將商務方法調用委派給bean時,遠程bean的EJBObject的skeleton必須請求這個事務的上下文。



轉自 www.chinacode.net 中國代碼聯盟新聞組
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗