ejb 中如何正確處理事務(轉載)

一、前言
在語音門戶的開發過程中,出現了在發生異常的情況下事務沒有正確會滾,導致數據的不一致型,在分析過程中發現是由於在處理異常方法不正確導致,所拋出的異常未能使事物回滾,那麼怎樣處理異常才能正確使事物回滾,下面將就EJB中的事務管理做出一些說明
二、EJB中事務處理的兩種方式
在EJB中處理事務有兩種方式,一種是由容器管理事務,一種是由Bean管理事務,在任何Bean中都可以使用容器管理事務,會話Bean和消息驅動Bean可以使用Bean管理事務,實體Bean不能使使用Bean管理事務。
(一)、容器管理事務
容器管理事務簡化了開發,因爲企業Bean不用編碼來顯式制定事務界限。代碼不包括開始結束事務的語句。典型的,容器會在一個企業Bean的方法被調用前立即開始一個事務,在這個方法退出以前提交這個事務。每個方法都關聯一個事務。在一個方法中不允許嵌套或多個的事務存在。容器管理事務不需要所有的方法都關聯事務。當部署一個Bean時,通過設定部署描述符中的事務屬性來決定方法是否關聯事務和如何關聯事務
1、 事務的屬性
一個事務的屬性控制了事務的使用範圍。圖 1-1說明了爲什麼控制事務的範圍很重要。圖中,method-A開始一個事務然後調用Bean-2中的method-B.它運行在method-A開始的事務中還是重新執行一個新的事務?結果要看method-B中的事務屬性

圖 1-1
一個事務屬性可能有下面的屬性之一:
?☆ Required
??☆ RequiresNew
??☆ Mandatory
??☆ NotSupported
??☆ Supports
??☆ Never
Required
??如果客戶端正在一個運行的事務中調用一個企業Bean的方法,這個方法就在這個客戶端的事務中執行。如果客戶端不關聯一個事務,這個容器在運行該方法前開始一個新的事務。
?Required屬性在許多事務環境中可以很好的工作,因此你可以把它作爲一個默認值,至少可以在早期開發中使用。因爲事務的屬性是在部署描述符中聲明的,在以後的任何時候修改它們都很容易。
RequiresNew
??如果客戶端在一個運行的事務中調用企業Bean的方法,容器的步驟是:
??1.掛起客戶端的事務
??2.開始一個新的事務
??3.代理方法的調用
??4.方法完成後重新開始客戶端的事務
??如果客戶端不關聯一個事務,容器運行這個方法以前同樣開始一個新的事務。如果你想保證該方法在任何時候都在一個新事物中運行,使用RequiresNew屬性。
Mandatory
??如果客戶端在一個運行的事務中調用企業Bean的方法,這個方法就在客戶端的事務中執行。如果客戶端不關聯事務,容器就拋出TransactionRequiredException 異常。
如果企業Bean的方法必須使用客戶端的事務,那麼就使用Mandatory屬性。
NotSupported
??如果客戶端在一個運行的事務中調用企業Bean的方法,這個容器在調用該方法以前掛起客戶端事務。方法執行完後,容器重新開始客戶端的事務。
??如果客戶端不關聯事務,容器在方法運行以前不會開始一個新的事務。爲不需要事務的方法使用NotSupported屬性。因爲事務包括整個過程,這個屬性可以提高性能。
Supports
??如果客戶端在一個運行的事務中調用企業Bean的方法,這個方法在客戶端的事務中執行,如果這個客戶端不關聯一個事務,容器運行該方法前也不會開始一個新的事務。因爲該屬性使方法的事務行爲不確定,你應該謹慎使用Supports屬性。
Never
??如果客戶端在一個運行的事務中調用企業Bean的方法,容器將拋出RemoteException異常。如果這個客戶端不關聯一個事務,容器運行該方法以前不會開始一個新的事務。
Summary of Transaction Attributes(事務屬性概要)
?? 表 1-1 列出了事務屬性的影響。事務T1和T2都被容器控制。T1是調用企業Bean方法的客戶端的事務環境。在大多數情況下,客戶端是其它的企業 Bean。T2是在方法執行以前容器啓動的事務。在表 1-1中,“None”的意思是這個商業方法不在容器控制事務中執行。然而,該商業方法中的數據庫操作可能在DBMS管理控制的事務中執行。
Setting Transaction Attributes (設定事務屬性)
??因爲事務屬性被保存在配置描述符中,他們會在J2EE應用程序開發的幾個階段被改變:創建企業Bean,應用程序裝配和部署。然而, 當創建這個Bean的時候指定它的屬性是企業Bean開發者的責任。只有將該組件裝配到一個更大的應用程序時可以由開發者修改該屬性,而不要期待J2EE應用程序部署者來指定該事務屬性。
表 1-1 事物屬性和範圍
事務屬性 客戶端事務 商業方法事務
Required None T2
T1 T1
RequiresNew None T2
T1 T2
Mandatory None error
T1 T1
NotSupported None None
T1 None
Supports None None
T1 T1
Never None None
T1 Error
?? 你可以爲整個企業Bean或者單個方法指定事務屬性。如果你爲整個企業Bean和它某個方法各指定一個事務屬性,爲該方法指定的事務屬性優先。當爲單個方法指定事務屬性時,不同類型企業Bean的要求也不同。會話Bean需要爲商業方法定義屬性屬性,但create方法不需要定義事務屬性。實體Bean需要爲商業方法、create方法、remove方法和查找(finder)方法定義事務屬性。Message-driven Bean需要爲 onMessage方法指定屬性事務,而且只能是Required和NotSupported其中之一。
(二) 、容器管理事務的回滾
在以下兩中情況下,事務將回滾。
第一, 如果產生一個系統異常,容器將自動回滾該事務。
系統異常是指應用程序的支撐服務出現異常。這樣的異常例子有:不能得到數據庫連接,數據庫滿造成SQL語句插入失敗,一個lookup方法找不到需要的對象等等。如果企業Bean遇到一個系統級的問題,它將拋出javax.ejb.EJBException,容器會把該異常包裝到一個 RemoteException異常中返回給客戶端。因爲EJBException是RutimeException的子類,所以你不需要將它列在 throws子句中。當一個系統異常發生時,EJB容器可能會銷燬企業Bean實例,因此係統異常不能被客戶端處理,它需要系統管理員的干涉
第二, 由於EJBException作爲系統異常,他繼承自RutimeException,所以經過驗證表明當拋出一個繼承自 RutimeException的自定義異常時EJB容器也會自動回滾該事務,拋出普通的繼承自Exception的應用程序異常容器不回自動回滾該事務
第三, 通過調用EJBContext接口SetRollbackOnly方法,Bean方法通知容器回滾該事務。如果Bean拋出一個普通的非繼承自RutimeException應用異常,事務將不會自動回滾,但可以調用SetRollbackOnly回滾。例如
public class serviceRegBean implements SessionBean {
SessionContext sessionContext;
public void ejbCreate() throws CreateException {
}
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void updateData() throws ThirdgsException {
try {
//更新操作一
//更新操作二
}
catch (Exception ex) {
//發生異常回滾事務
sessionContext.setRollbackOnly();
ex.printStackTrace();
throw new ThirdgsException();
}
}
}
其中的ThirdgsException爲繼承自Exception的異常
(三) 、Bean管理事務
容器管理事務不支持嵌套事務,Bean管理事務支持嵌套事務,所以需要嵌套事務時可以採用Bean管理事務,使用Bean管理事務需要我們顯式的設置事務的屬性,需要我們自己編碼管理事務,我門可以採用下面兩種方式在Bean中管理事務
1、JDBC事務
JDBC 事務通過DBMS事務管理器來控制。你可能會爲了使用會話Bean中的原有代碼而採用JDBC事務將這些代碼封裝到一個事務中。使用JDBC事務,要調用 java.sql.Connection接口的commit和rollback方法。事務啓動是隱式的。一個事務的從最近的提交、回滾或連接操作後的第一個SQL的語句開始。(這個規則通常是正確的,但可能DBMS廠商的不同而不同),例如
public void ship (String productId, String orderId, int quantity) {
try {
//需要通知DBMS不要自動提交每個SQL語句
con.setAutoCommit(false);
updateOrderItem(productId, orderId);
updateInventory(productId, quantity);
con.commit();

} catch (Exception ex) {
try {
con.rollback();
throw new EJBException("Transaction failed: " +
ex.getMessage());
} catch (SQLException sqx) {
throw new EJBException("Rollback failed: " +
sqx.getMessage());
}
}
}
2、JTA事務
JTA 是Java Transaction API 的縮寫。這些API 允許你用獨立於具體的事務管理器實現的方法確定事務界限。J2EE SDK 事務管理器通過Java事務服務(Java Transaction Service, JTS)實現。但是你的代碼並不直接調用JTS中的方法,而是調用JTA 方法來替代,JTA方法會調用底層的JTS實現。
JTA事務被J2EE 事務管理器管理。你可能需要使用一個JTA事務,因爲它能夠統一操作不同廠商的數據庫。一個特定DBMS的事務管理器不能工作在不同種類的數據庫上。然而J2EE事務管理器仍然有一個限制??它不支持嵌套事務。就是說,它不能在前一個事務結束前啓動另一個事務。
??要自己確定事務界限,可以調用 javax.transaction.UserTransaction接口的begin、commit和rollback方法來確定事務界限(該接口只能在SessionBean中使用,實體Bean不允許使用用戶自定義的)。下面選自TellerBean類的代碼示範了UserTransaction的用法。begin和commit方法確定了數據庫操作的事務界限,如果操作失敗則調用rollback回滾事務並拋出EJBException異常。

public void withdrawCash(double amount) {
UserTransaction ut = context.getUserTransaction();
try {
ut.begin();
updateChecking(amount);
machineBalance -= amount;
insertMachine(machineBalance);
ut.commit();
} catch (Exception ex) {
try {
ut.rollback();
} catch (SystemException syex) {
throw new EJBException
("Rollback failed: " + syex.getMessage());
}
throw new EJBException
("Transaction failed: " + ex.getMessage());
}
}
三、總結
以上是我在工作中遇到問題後,查閱資料後,結合資料和實踐作出的一些總結,如果有謬誤之處,望指出,大家一起探討,謝謝!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章