第14章 事務(wù)
Dale Green著
JSP WU 譯
一個典型的企業(yè)應(yīng)用程序在一個或多個數(shù)據(jù)庫中訪問和存儲信息。因為這些信息對于商業(yè)操作非常重要,它必須精確、實時、可靠。如果允許多個程序同時更新相同的數(shù)據(jù),就會破壞數(shù)據(jù)的完整性。如果在一個商業(yè)交易處理過程中,部分數(shù)據(jù)被更新后系統(tǒng)崩潰也將破壞數(shù)據(jù)完整性。事務(wù)通過預防以上情況的發(fā)生確保數(shù)據(jù)的完整性。事務(wù)控制多個應(yīng)用程序?qū)?shù)據(jù)庫的并發(fā)操作。如果發(fā)生系統(tǒng)崩潰,事務(wù)確保恢復的數(shù)據(jù)崩潰前將保持一致。
本章內(nèi)容:
什么是事務(wù)
容器管理事務(wù)
事務(wù)的屬性
回滾容器管理事務(wù)
同步會話bean實例變量
容器管理事務(wù)中不允許使用的方法
Bean 管理事務(wù)
JDBC事務(wù)
JTA? 事務(wù)
非提交返回事務(wù)
在Bean管理事務(wù)中不允許使用的方法
企業(yè)Bean事務(wù)摘要
事務(wù)超時
隔離級別
更新多個數(shù)據(jù)庫
Web 組件事務(wù)
?
一.什么是事務(wù)
模擬一個商業(yè)交易,應(yīng)用程序需要完成幾個步驟。例如,一個財物應(yīng)用程序,可能會將資金從經(jīng)常性帳戶(checking account)轉(zhuǎn)到儲蓄性賬戶(saving account),該交易的偽碼表示如下:
begin transaction
debit checking account
credit savings account
update history log
commit transaction
三個步驟要么全部完成,要么一個都不做。否則數(shù)據(jù)完整性將被破壞。因為事務(wù)中的所有步驟被看作一個統(tǒng)一的整體,所以事務(wù)一般被定義為一個不可分割的工作單元。
結(jié)束事務(wù)有兩種方法:提交或者回滾。當一個事務(wù)提交,數(shù)據(jù)修改被保存。如果事務(wù)中有一個步驟失敗,事務(wù)就回滾,這個事務(wù)中的已經(jīng)執(zhí)行的動作被撤銷。例如在上面的偽碼中,如果在處理第二步的時候硬盤驅(qū)動器崩潰,事務(wù)的第一步將被撤銷。盡管事務(wù)失敗,數(shù)據(jù)的完整性不會被破壞,因為帳目仍然保持平衡。
前面?zhèn)未a中,begin和commit標明了事務(wù)的界限。當設(shè)計一個企業(yè)Bean的時候,你要決定怎樣通過容器管理或bean管理事務(wù)來指定事務(wù)界限。
二.容器管理事務(wù)
在容器管理事務(wù)的企業(yè)Bean中,EJB容器來設(shè)定事務(wù)界線。你能夠在任何企業(yè)Bean中使用容器管理事務(wù):會話Bean、實體Bean或者 Message-driven Bean。容器管理事務(wù)簡化了開發(fā),因為企業(yè)Bean不用編碼來顯式制定事務(wù)界限。代碼不包括開始結(jié)束事務(wù)的語句。典型的,容器會在一個企業(yè)Bean的方法被調(diào)用前立即開始一個事務(wù),在這個方法退出以前提交這個事務(wù)。每個方法都關(guān)聯(lián)一個事務(wù)。在一個方法中不允許嵌套或多個的事務(wù)存在。容器管理事務(wù)不需要所有的方法都關(guān)聯(lián)事務(wù)。當部署一個Bean時,通過設(shè)定部署描述符中的事務(wù)屬性來決定方法是否關(guān)聯(lián)事務(wù)和如何關(guān)聯(lián)事務(wù)。
事務(wù)的屬性
一個事務(wù)的屬性控制了事務(wù)的使用范圍。圖 14-1說明了為什么控制事務(wù)的范圍很重要。圖中,method-A開始一個事務(wù)然后調(diào)用Bean-2中的method-B.它運行在method-A開始的事務(wù)中還是重新執(zhí)行一個新的事務(wù)?結(jié)果要看method-B中的事務(wù)屬性。
圖 14-1 Transaction Scope
一個事務(wù)屬性可能有下面的屬性之一:
☆ Required
☆ RequiresNew
☆ Mandatory
☆ NotSupported
☆ Supports
☆ Never
Required
如果客戶端正在一個運行的事務(wù)中調(diào)用一個企業(yè)Bean的方法,這個方法就在這個客戶端的事務(wù)中執(zhí)行。如果客戶端不關(guān)聯(lián)一個事務(wù),這個容器在運行該方法前開始一個新的事務(wù)。
Required屬性在許多事務(wù)環(huán)境中可以很好的工作,因此你可以把它作為一個默認值,至少可以在早期開發(fā)中使用。因為事務(wù)的屬性是在部署描述符中聲明的,在以后的任何時候修改它們都很容易。
RequiresNew
如果客戶端在一個運行的事務(wù)中調(diào)用企業(yè)Bean的方法,容器的步驟是:
1.掛起客戶端的事務(wù)
2.開始一個新的事務(wù)
3.代理方法的調(diào)用
4.方法完成后重新開始客戶端的事務(wù)
如果客戶端不關(guān)聯(lián)一個事務(wù),容器運行這個方法以前同樣開始一個新的事務(wù)。如果你想保證該方法在任何時候都在一個新事物中運行,使用RequiresNew屬性。
Mandatory
如果客戶端在一個運行的事務(wù)中調(diào)用企業(yè)Bean的方法,這個方法就在客戶端的事務(wù)中執(zhí)行。如果客戶端不關(guān)聯(lián)事務(wù),容器就拋出TransactionRequiredException 異常。
如果企業(yè)Bean的方法必須使用客戶端的事務(wù),那么就使用Mandatory屬性。
NotSupported
如果客戶端在一個運行的事務(wù)中調(diào)用企業(yè)Bean的方法,這個容器在調(diào)用該方法以前掛起客戶端事務(wù)。方法執(zhí)行完后,容器重新開始客戶端的事務(wù)。
如果客戶端不關(guān)聯(lián)事務(wù),容器在方法運行以前不會開始一個新的事務(wù)。為不需要事務(wù)的方法使用NotSupported屬性。因為事務(wù)包括整個過程,這個屬性可以提高性能。
Supports
如果客戶端在一個運行的事務(wù)中調(diào)用企業(yè)Bean的方法,這個方法在客戶端的事務(wù)中執(zhí)行,如果這個客戶端不關(guān)聯(lián)一個事務(wù),容器運行該方法前也不會開始一個新的事務(wù)。因為該屬性使方法的事務(wù)行為不確定,你應(yīng)該謹慎使用Supports屬性。
Never
如果客戶端在一個運行的事務(wù)中調(diào)用企業(yè)Bean的方法,容器將拋出RemoteException異常。如果這個客戶端不關(guān)聯(lián)一個事務(wù),容器運行該方法以前不會開始一個新的事務(wù)。
Summary of Transaction Attributes(事務(wù)屬性概要)
表 14-1 列出了事務(wù)屬性的影響。事務(wù)T1和T2都被容器控制。T1是調(diào)用企業(yè)Bean方法的客戶端的事務(wù)環(huán)境。在大多數(shù)情況下,客戶端是其它的企業(yè)Bean。T2是在方法執(zhí)行以前容器啟動的事務(wù)。在表 14-1中,“None”的意思是這個商業(yè)方法不在容器控制事務(wù)中執(zhí)行。然而,該商業(yè)方法中的數(shù)據(jù)庫操作可能在DBMS管理控制的事務(wù)中執(zhí)行。
Setting Transaction Attributes (設(shè)定事務(wù)屬性)
因為事務(wù)屬性被保存在配置描述符中,他們會在J2EE應(yīng)用程序開發(fā)的幾個階段被改變:創(chuàng)建企業(yè)Bean,應(yīng)用程序裝配和部署。然而, 當創(chuàng)建這個Bean的時候指定它的屬性是企業(yè)Bean開發(fā)者的責任。只有將該組件裝配到一個更大的應(yīng)用程序時可以由開發(fā)者修改該屬性,而不要期待J2EE應(yīng)用程序部署者來指定該事務(wù)屬性。
表 14-1 事物屬性和范圍? |
||
事務(wù)屬性 |
客戶端事務(wù) |
商業(yè)方法事務(wù) |
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 |
你可以為整個企業(yè)Bean或者單個方法指定事務(wù)屬性。如果你為整個企業(yè)Bean和它某個方法各指定一個事務(wù)屬性,為該方法指定的事務(wù)屬性優(yōu)先。當為單個方法指定事務(wù)屬性時,不同類型企業(yè)Bean的要求也不同。會話Bean需要為商業(yè)方法定義屬性屬性,但create方法不需要定義事務(wù)屬性。實體Bean需要為商業(yè)方法、create方法、remove方法和查找(finder)方法定義事務(wù)屬性。Message-driven Bean需要為onMessage方法指定屬性事務(wù),而且只能是Required和NotSupported其中之一。
容器管理事務(wù)的回滾
在以下兩中情況下,事務(wù)將回滾。第一,如果產(chǎn)生一個系統(tǒng)異常,容器將自動回滾該事務(wù)。第二,通過調(diào)用EJBContext接口SetRollbackOnly方法,Bean方法通知容器回滾該事務(wù)。如果Bean拋出一個應(yīng)用異常,事務(wù)將不會自動回滾,但可以調(diào)用SetRollbackOnly回滾。對于一個系統(tǒng)和應(yīng)用的異常,參考第5章的處理異常一節(jié)。
下面這個例子的代碼在j2eetorial/examples/src/bank目錄下。在命令行窗口下進入j2eetutorial/examples目錄執(zhí)行ant bank命令編譯這些代碼,執(zhí)行 ant create-bank-table命令創(chuàng)建要用到的表。一個BankApp.ear樣本文件在j2eetutorial/examples/ears目錄下。通過BnankEJB 實例的transferToSaving方法來說明setRollbackOnly方法的用法。如果余額檢查出現(xiàn)負數(shù),那么transferToSaving調(diào)用setRollBackOnly回滾事務(wù)并拋出一個應(yīng)用程序異常(InsufficientBalanceException)。updateChecking和updateSaving 方法更新數(shù)據(jù)表。如果更新失敗,這兩個方法拋出SQLException異常而transgerToSaving方法拋出EJBException異常。因為EJBException是一個系統(tǒng)異常,它使容器事務(wù)自動回滾事務(wù)。TransferTuSaving 方法的代碼如下:
public void transferToSaving(double amount) throws
?? InsufficientBalanceException? {
? checkingBalance -= amount;
?? savingBalance += amount;
? try {
???? ?updateChecking(checkingBalance);
????? if (checkingBalance < 0.00) {
???????? context.setRollbackOnly();
???????? throw new InsufficientBalanceException();
????? }
????? updateSaving(savingBalance);
?? } catch (SQLException ex) {
?????? throw new EJBException
??????????("Transaction failed due to SQLException: "
??????????+ ex.getMessage());
?? }
}
當一個容器回滾一個事務(wù),它總是會撤消事務(wù)中已執(zhí)行的SQL語句造成的數(shù)據(jù)改動。然而,僅僅在實體Bean中容器回滾才會改變Bean的實例變量(與數(shù)據(jù)庫狀態(tài)有關(guān)的字段)。(這是因為容器會自動調(diào)用實體Bean的ejbLoad方法,該方法從數(shù)據(jù)庫中讀入實例變量的值。)當發(fā)生回滾,會話Bean必須顯式重新設(shè)置所有被事務(wù)改動過的實例變量。重設(shè)會話Bean的實例變量最簡單的方法是實現(xiàn)SessionSynchronization接口。
同步會話Bean的實例變量
SessionSynchronization接口是可選的,它允許你在Bean的實例變量和它們在數(shù)據(jù)庫中的相應(yīng)值之間保持同步。容器會在事務(wù)的幾個主要階段調(diào)用SessionSynchronization接口的對應(yīng)方法—afterBegin、beforeCompletion和afterCompletion。
AfterBegin方法通知Bean實例一個新的事務(wù)已經(jīng)開始。容器在調(diào)用商業(yè)方法以前立即調(diào)用afterBegin方法。afterBegin方法是從數(shù)據(jù)庫中讀入實例變量值的最佳位置。例如,在BanBean類中,在afterBegin方法中從讀入了CheckingBalance和savingBalance變量的值:
? public void afterBegin() {
? System.out.println("afterBegin()");
?? try {
????? checkingBalance = selectChecking();
????? savingBalance = selectSaving();
?? } catch (SQLException ex) {
?????? throw new EJBException("afterBegin Exception: " +
?????????? ex.getMessage());
?? }
}
商業(yè)方法方法完成以后,容器調(diào)用beforeCompletion方法,不過僅僅是在事務(wù)提交以前。BeforeCompletion方法是會話Bean回滾事務(wù)的最后時機(通過調(diào)用setRollbackOnly方法).如果會話Bean還沒有實例變量的值更新數(shù)據(jù)庫,就在beforCompletion方法里實現(xiàn)。
afterCompletion方法指出事務(wù)已經(jīng)完成。它只有一個布爾型的參數(shù),true表示事務(wù)被正確提交false表示事務(wù)回滾。如果事務(wù)回滾,會話Bean可以在該方法中從數(shù)據(jù)庫中重新讀取它的實例變量值:
public void afterCompletion(boolean committed) {
? System.out.println("afterCompletion: " + committed);
?? if (committed == false) {
????? try {
???????? checkingBalance = selectChecking();
???????? savingBalance = selectSaving();
????? } catch (SQLException ex) {
????????? throw new EJBException("afterCompletion SQLException:
???????? " + ex.getMessage());
????? }
?? }
}
容器管理事務(wù)中不允許使用的方法
你不應(yīng)該調(diào)用可能干擾容器設(shè)置的事務(wù)界線的方法,下面列出了所有禁止的方法:
☆ java.sql.Connection接口的commit、setAutoCommit和rollback方法
☆ javax.ejb.EJBContext 接口的getUserTransaction方法
☆ javax.transaction.UserTransaction接口的所有方法
然而你可以在Bean管理事務(wù)中使用這些方法設(shè)置事務(wù)界限。
三.Bean管理事務(wù)
在一個Bean管理事務(wù)中,會話Bean或者Message-driven Bean是用代碼顯式設(shè)置事務(wù)界線的。實體Bean不能使用Bean管理事務(wù),只能使用容器管理的事務(wù)。雖然容器管理事務(wù)Bean需要較少的代碼,但它也有一個局限:方法執(zhí)行時,它只能關(guān)聯(lián)一個事務(wù)或不關(guān)聯(lián)任何事務(wù)。如果這個局限使你Bean編碼困難,你應(yīng)該考慮使用Bean管理事務(wù)。(譯者:實際上J2EE服務(wù)器不支持嵌套事物,那么Bean管理事務(wù)唯一的優(yōu)點就是可以在一個方法中一次啟動多個事務(wù))
下面的偽碼很好說明了Bean管理事對商業(yè)邏輯的緊密控制。通過檢查各種條件,偽碼決定是否在商業(yè)方法中啟動或停止不同的事務(wù)。
begin transaction
...
update table-a
...
if (condition-x)
?? commit transaction
else if (condition-y)
?? update table-b
?? commit transaction
else
?? rollback transaction
?? begin transaction
?? update table-c
?? commit transaction
當為會話Bean或Message-driver Bean的Bean管理事務(wù)編碼時,你必須決定是使用jdbc或者JTA事務(wù)。下面的內(nèi)容論述了兩種事務(wù)類型。
JDBC 事務(wù)
JDBC事務(wù)通過DBMS事務(wù)管理器來控制。你可能會為了使用會話Bean中的原有代碼而采用JDBC事務(wù)將這些代碼封裝到一個事務(wù)中。使用JDBC事務(wù),要調(diào)用java.sql.Connection接口的commit和rollback方法。事務(wù)啟動是隱式的。一個事務(wù)的從最近的提交、回滾或連接操作后的第一個SQL的語句開始。(這個規(guī)則通常是正確的,但可能DBMS廠商的不同而不同)
代碼資源
下面的例子在j2eetutorial/examples/src/ejb/warehouse目錄下。在命令行窗口中進入j2eetutorial/examples目錄執(zhí)行ant bank命令編譯這些源文件,執(zhí)行ant create-warehouse-table命令創(chuàng)建要用到的表,一個樣本W(wǎng)arehouseApp.ear文件在j2eetutorial/example/ears 目錄下。
下面的代碼來自WarehouseEJB例子,一個會話Bean通過使用Connection接口的方法來劃定Bean管理事務(wù)界限。ship方法以調(diào)用名為con的連接對象的setAutoCommit方法開始,該方法通知DBMS不要自動提交每個SQL語句。接下來ship 方法更新order_item和inventory數(shù)據(jù)表。如果更新成功,這個事務(wù)就會被提交。如果出現(xiàn)異常,事務(wù)就回滾。
public void ship (String productId, String orderId, int
quantity) {
? try {
????? 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());
?????? }
?? }
}
JTA 事務(wù)
JTA是Java Transaction API 的縮寫。這些API 允許你用獨立于具體的事務(wù)管理器實現(xiàn)的方法確定事務(wù)界限。J2EE SDK 事務(wù)管理器通過Java事務(wù)服務(wù)(Java Transaction Service, JTS)實現(xiàn)。但是你的代碼并不直接調(diào)用JTS中的方法,而是調(diào)用JTA方法來替代,JTA方法會調(diào)用底層的JTS實現(xiàn)。
JTA事務(wù)被J2EE?事務(wù)管理器管理。你可能需要使用一個JTA事務(wù),因為它能夠統(tǒng)一操作不同廠商的數(shù)據(jù)庫。一個特定DBMS的事務(wù)管理器不能工作在不同種類的數(shù)據(jù)庫上。然而J2EE事務(wù)管理器仍然有一個限制——它不支持嵌套事務(wù)。就是說,它不能在前一個事務(wù)結(jié)束前啟動另一個事務(wù)。
下面例子的源代碼在j2eetutorial/examples/src/ejb/teller目錄下,在命令行窗口進入j2eetutorial/examples目錄,執(zhí)行ant teller命令編譯這些源文件,執(zhí)行ant create-bank-teller命令創(chuàng)建要用到的表。一個樣本TellerApp.ear文件在j2eetutorial/examples/ears目錄下。
要自己確定事務(wù)界限,可以調(diào)用javax.transaction.UserTransaction接口的begin、commit和rollback方法來確定事務(wù)界限(該接口只能在SessionBean中使用,實體Bean不允許使用用戶自定義的)。下面選自TellerBean類的代碼示范了UserTransaction的用法。begin和commit方法確定了數(shù)據(jù)庫操作的事務(wù)界限,如果操作失敗則調(diào)用rollback回滾事務(wù)并拋出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());
??? }
}
非提交返回事務(wù)
使用Bean管理事務(wù)的無狀態(tài)會話Bean在事務(wù)返回前必須提交或者返回事務(wù),而有狀態(tài)的會話Bean沒有這個限制。
對于使用JTA事務(wù)的有狀態(tài)會話Bean,Bean實例和事務(wù)的關(guān)聯(lián)越過大量用戶調(diào)用被保持,甚至被調(diào)用的每個商業(yè)方法都打開和關(guān)閉數(shù)據(jù)庫連接,該市無關(guān)聯(lián)也不斷開,直到事務(wù)完成(或回滾)。
對于使用JDBC事務(wù)的有狀態(tài)會話Bean,JDBC連接越過用戶調(diào)用保持Bean和事務(wù)之間的關(guān)聯(lián)。連接關(guān)閉,事務(wù)關(guān)聯(lián)將被釋放。
在Bean管理事務(wù)中不允許使用的方法
在Bean管理的事務(wù)中不能調(diào)用EJBContext接口的getRollbackOnly和setRollbackOnly方法,這兩個方法只能在容器管理事務(wù)中被調(diào)用。在Bean管理事務(wù)中,應(yīng)調(diào)用UserTransaction接口的getStatus和rollback方法。
四.企業(yè)Bean事務(wù)摘要
如果你不能確定怎么在企業(yè)Bean中使用事務(wù),可以用這個小技巧:在Bean的部署描述符中,制定事務(wù)類型為容器管理,把整個Bean(所有方法)的事務(wù)屬性設(shè)置為Required。大多數(shù)情況下,這個配置可以滿足你的事務(wù)需求。
表14-2列出了不同類型的企業(yè)Bean所允許使用的事務(wù)類型。實體Bean只能使用容器管理事務(wù),但可以在部署描述符中配置事務(wù)屬性,并可以調(diào)用EJBContext接口的setRollbackOnly方法來回滾事務(wù)。
表 14-2 企業(yè)Bean 允許的事務(wù)類型 |
||||
企業(yè)Bean 類型 |
容器管理事務(wù) |
Bean管理事務(wù) |
? | |
JTA |
JDBC |
? | ||
實體Bean |
Y |
N |
N |
? |
會話Bean |
Y |
Y |
Y |
? |
Message-driven |
Y |
Y |
Y |
? |
會話Bean既可以使用容器管理事務(wù)也可以使用Bean管理事務(wù)。Bean管理事務(wù)又有兩種類型:JDBC事務(wù)和JTA事務(wù)。JDBC事務(wù)使用Connection接口的commit和rollback方法來劃分事務(wù)界限。JTA事務(wù)使用UserTransaction接口的begin、commit和rollback方法來劃分事務(wù)界限。
在Bean管理事務(wù)的會話Bean中,混合使用JTA事務(wù)和JDBC事務(wù)是可能的。但是我不推薦這樣使用,因為這樣會造成代碼的調(diào)試和維護都很困難。
Message-driver Bean和會話Bean一樣既可以使用容器管理事務(wù)也可以使用Bean管理事務(wù)。
五.事務(wù)超時
對于容器管理事務(wù),事務(wù)超時間隔是通過設(shè)置default.properties文件中ransaction.timeout屬性的值來確定的,該文件在J2EE SDK安裝目錄的config子目錄下。如下例將事務(wù)超時間隔設(shè)置為5秒鐘:
transaction.timeout=5
這樣,當事務(wù)在5秒鐘內(nèi)還沒有完成,容器將回滾該事務(wù)。
J2EE SDK安裝后,超時間隔的缺省值為0,表示不計算超時,無論事務(wù)執(zhí)行多長時間,除非異常出錯回滾,一直等待事務(wù)完成。
只有使用容器管理事務(wù)的企業(yè)Bean才會受到transaction.timeout屬性值的影響。Bean管理的JTA事務(wù)使用UserTransaction接口的setTransactionTimeout方法來設(shè)置事務(wù)超時間隔。
六.隔離級別
事務(wù)不僅保證事務(wù)界限內(nèi)的數(shù)據(jù)庫操作全部完成(或回滾)同時還隔離數(shù)據(jù)庫更新語句。隔離級別描述被修改的數(shù)據(jù)對其他事物的可見度。
假如一個應(yīng)用程序在事務(wù)中修改一個顧客的電話號碼,在事務(wù)結(jié)束前另一個應(yīng)用程序要讀取該條記錄的電話號碼。那么第二個應(yīng)用程序是讀取修改過但還沒提交的數(shù)據(jù),還是讀取未修改前的老數(shù)據(jù)呢?答案就取決于事務(wù)的隔離級別。如果事務(wù)允許其他程序讀取未提交的數(shù)據(jù),會因為不用等待事務(wù)結(jié)束而提高性能,同時也有一個缺點,如果事務(wù)回滾,其他應(yīng)用程序讀取的將是錯誤的數(shù)據(jù)。
容器管理持久性(CMP)的實體Bean的事務(wù)級別無法修改,它們使用DBMS的默認個理解別,通常是READ_COMMITTED。
Bean管理持久性(BMP)的實體Bean和兩種會話Bean都可以通過在程序中調(diào)用底層DBMS提供的API來設(shè)置事務(wù)級別。例如,一個DBMS可能允許你如下調(diào)用setTransactionIsolation方法將隔離級別設(shè)置成可讀取未提交數(shù)據(jù):
Connection con;
...
con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
不要在事務(wù)執(zhí)行期間更改隔離級別,通常隔離級別的更改會引起DBMS產(chǎn)生一次隱式提交。因為隔離級別的控制會跟具體的DBMS廠商不同而不同,具體的信息請參考DBMS的文檔。J2EE平臺規(guī)范不包括隔離級別標準。
七.更新多個數(shù)據(jù)庫
J2EE事務(wù)管理器控制著除了Bean管理的JDBC事務(wù)以外的所有企業(yè)Bean事務(wù),它允許企業(yè)Bean在同一個事務(wù)中更新多個數(shù)據(jù)庫。下面示范在單個事務(wù)中更新多個數(shù)據(jù)庫的兩個應(yīng)用。
圖14-2中,客戶端調(diào)用Bean-A的商業(yè)方法,商業(yè)方法啟動一個事務(wù),更新數(shù)據(jù)庫X和Y,Bean-A的商業(yè)方法有調(diào)用Bean-B的商業(yè)方法,Bean-B的商業(yè)方法更新數(shù)據(jù)庫Z然后返回事務(wù)的控制權(quán)給Bean-A的商業(yè)方法,由Bean-A提交該事務(wù)。三個數(shù)據(jù)庫的更新都在同一個事務(wù)中發(fā)生。
圖 14-2 更新多個數(shù)據(jù)庫
圖14-3中,客戶端調(diào)用Bean-A的商業(yè)方法,該商業(yè)方法啟動一個事務(wù)并更新數(shù)據(jù)庫X,然后調(diào)用另一個J2EE服務(wù)器中的Bean-B的方法,該方法更新數(shù)據(jù)庫Y。J2EE服務(wù)器保證兩個數(shù)據(jù)庫的更新都在同一個事務(wù)中進行(筆者認為應(yīng)該是第一個J2EE服務(wù)器的事務(wù)管理器管理整個事物)。
圖 14-3 跨越J2EE服務(wù)器更新多個數(shù)據(jù)庫
八.Web 組件事務(wù)
Web組件中劃分事務(wù)界限可以使用java.sql.Connection接口和javax.transaction.UserTransaction接口中的任意一個。跟Bean管理事務(wù)的會話Bean使用一樣的兩個接口。這兩個接口的使用方法參考前面幾節(jié)的內(nèi)容。Web組件事務(wù)的例子在第10章Servlet技術(shù)第四節(jié)共享信息的訪問數(shù)據(jù)庫小節(jié)講述過。