JDBC事務(wù)優(yōu)化

作者:Jack Shirazi

開發(fā)通過ACID測試的應(yīng)用程序

事務(wù)使得開發(fā)人員的工作變得簡單多了。通過在JDBC API和諸如Oracle9i的關(guān)系數(shù)據(jù)庫中使用事務(wù)功能,在更新多用戶應(yīng)用程序時(shí),你可以把數(shù)據(jù)遭破壞的可能性降到最低。然而,事務(wù)需要處理開銷,與免費(fèi)事務(wù)應(yīng)用程序(更容易被破壞)相比較,它會(huì)降低系統(tǒng)的性能。那么,當(dāng)使用事務(wù)時(shí),什么才是保持性能的最好方法?

最佳的性能調(diào)優(yōu)建議是避免做那些沒必要做的事情。事務(wù)處理是數(shù)據(jù)庫的大量工作,而且數(shù)據(jù)庫默認(rèn)地維護(hù)多種資源以確保事務(wù)具有ACID(原子性,一致性,隔離性和持續(xù)性)屬性(查看"ACID Transaction Properties"工具欄獲取詳細(xì)信息)。這些數(shù)據(jù)庫資源管理多個(gè)數(shù)據(jù)并發(fā)操作以及提交和回滾操作,從而保證ACID事務(wù)屬性。如果你能減少數(shù)據(jù)庫的此類操作,就將提高應(yīng)用程序的性能。讓我們看一些避免處理開銷并提高事務(wù)性能的方法。

自動(dòng)提交模式

最大限度減少事務(wù)開銷的第一個(gè)方法是通過把多個(gè)操作移到一個(gè)單一事務(wù)中來合并事務(wù)。默認(rèn)情況下,JDBC連接工作在自動(dòng)提交模式下,這就意味著每個(gè)發(fā)送到數(shù)據(jù)庫的操作都會(huì)作為獨(dú)立事務(wù)自動(dòng)執(zhí)行。在這種情況下,每個(gè)Statement.execute()方法調(diào)用都如同由一條BEGIN TRANSACTION命令開始,并由一條COMMIT命令結(jié)束。

關(guān)閉自動(dòng)提交模式并且明確定義事務(wù)需要進(jìn)行大量額外的工作,因?yàn)槟惚仨毷謩?dòng)添加事務(wù)劃分語句(COMMIT和ROLLBACK)。但是合并事務(wù)可以減少性能開銷,特別是當(dāng)你對你的系統(tǒng)進(jìn)行伸縮時(shí)。(下面的"部分會(huì)涉及到合并更新事務(wù)的技術(shù)細(xì)節(jié)。)在重負(fù)荷系統(tǒng)中,事務(wù)開銷意義重大。開銷越低,系統(tǒng)的可伸縮性就越好。

簡單地使用Connection.setAutoCommit(false)命令來關(guān)閉自動(dòng)提交模式。

JDBC API還提供了一個(gè)Connection.getAutoCommit()方法來返回當(dāng)前的自動(dòng)提交模式。當(dāng)你關(guān)閉了自動(dòng)提交模式,你將需要使用兩個(gè)事務(wù)劃分方法:Connection.commit()和Connection.rollback()。

當(dāng)人工控制事務(wù)時(shí),需要遵循以下幾條原則:使事務(wù)盡可能保持簡短,不要在一個(gè)事務(wù)中包含很多操作使它們變得非常冗長。(使事務(wù)打開并保持行開鎖狀態(tài),會(huì)影響其他事務(wù)并降低可伸縮性。)然而,如果幾項(xiàng)操作可以一項(xiàng)接一項(xiàng)地執(zhí)行,那么就把它們合并到一個(gè)事務(wù)中。

合并操作可能需要在你的SQL語句中增加額外的條件邏輯,并且可能需要臨時(shí)表。不管這個(gè)開銷,合并事務(wù)會(huì)更加有效,因?yàn)閿?shù)據(jù)庫可以在一個(gè)步驟內(nèi)獲得所有需要的鎖,并在一個(gè)步驟內(nèi)釋放它們。

當(dāng)自動(dòng)提交模式?jīng)]有關(guān)閉時(shí),它所引起的更多事務(wù)會(huì)產(chǎn)生更多的通信開銷,更多的鎖定和釋放時(shí)間,以及與其他會(huì)話發(fā)生沖突的更大可能性。

批量更新

批量更新簡單地說就是在一個(gè)事務(wù)和一個(gè)數(shù)據(jù)庫調(diào)用中將多個(gè)DML語句(例如插入、更新和刪除)發(fā)送到數(shù)據(jù)庫。JDBC通過Statement.addBatch()和Statement.executeBatch()方法支持這項(xiàng)功能。批量更新的技巧相當(dāng)簡單,在下文中會(huì)加以說明。記住關(guān)閉自動(dòng)提交模式(確保一個(gè)批處理作為一個(gè)事務(wù)執(zhí)行),并且當(dāng)你完成后這一切后,明確提交批事務(wù)。

清單 1 中的示例使用了普通的JDBC Statement對象。另外,JDBC API提供了一個(gè)PreparedStatement類,它也可以用參數(shù)表示SQL語句。

此外,當(dāng)你使用PreparedStatement 對象來代替Statement對象時(shí),Oracle的JDBC批處理實(shí)施就可以得到優(yōu)化。在Oracle JDBC中,Statement對象不會(huì)在一次網(wǎng)絡(luò)傳輸中傳送所有成批的SQL語句。由于這個(gè)限制,當(dāng)成批傳送語句時(shí)可以使用PreparedStatement對象,因?yàn)镻reparedStatement在一次批處理中會(huì)傳送所有的語句。

清單 2 給出了使用參數(shù)語句和PreparedStatement對象的相同批處理技巧。

借助于所有批處理語句相同的查詢計(jì)劃,在PreparedStatement對象中利用參數(shù)語句使數(shù)據(jù)庫進(jìn)一步優(yōu)化批處理。如果沒有參數(shù)設(shè)定,語句就會(huì)各不相同,因而數(shù)據(jù)庫就不能重復(fù)使用查詢計(jì)劃。

雖然這種方法經(jīng)常可以提高性能,但應(yīng)注意以下幾點(diǎn):處理開銷與創(chuàng)建查詢計(jì)劃的聯(lián)合將導(dǎo)致第一次執(zhí)行SQL語句時(shí)會(huì)比使用普通Statement對象時(shí)運(yùn)行得更慢,而隨后準(zhǔn)備好的執(zhí)行語句將會(huì)快很多。(開發(fā)人員經(jīng)常把首次PreparedStatement批處理移動(dòng)到應(yīng)用程序中對時(shí)間要求低的部分加以執(zhí)行。)使用PreparedStatement對象將比使用Statement對象更有效,特別是當(dāng)使用超過50條語句的大批量處理時(shí)。

以上的示例使用了JDBC規(guī)范所定義的標(biāo)準(zhǔn)批處理模式。Oracle的JDBC實(shí)施提供了一種可選擇的批處理模式,它使用了一種被稱作OraclePreparedStatement.setExecuteBatch(int)的新方法。在這種模式下,預(yù)設(shè)的語句被自動(dòng)保存在客戶端,直到語句的數(shù)量與setExecuteBatch(int)中的參數(shù)所定義的"批量值"相等。這樣一來,積累的語句在一次傳送中被發(fā)送到數(shù)據(jù)庫。Oracle所推薦的這種模式在某些情況下會(huì)比標(biāo)準(zhǔn)的批處理模式更快。當(dāng)使用它的時(shí)候,調(diào)整批量值來優(yōu)化你的應(yīng)用程序中事務(wù)的性能。Oracle模式惟一需要注意的一點(diǎn)是:它不是標(biāo)準(zhǔn)的--它使用官方JDBC規(guī)范所不支持的擴(kuò)展功能。

事務(wù)隔離級(jí)別

事務(wù)被定義為全有或全無操作。一個(gè)事務(wù)的ACID屬性確保每件事情都發(fā)生在一個(gè)事務(wù),如同在事務(wù)期間在數(shù)據(jù)庫中沒有發(fā)生其他操作。由此可見,對數(shù)據(jù)庫來說,確保ACID屬性有很多工作要做。

JDBC Connection界面定義了五種事務(wù)隔離級(jí)別(在下面說明)。并不是所有的數(shù)據(jù)庫都支持所有的級(jí)別。例如,Oracle9i只支持TRANSACTION_READ_COMMITTED和TRANSACTION_ SERIALIZABLE這兩個(gè)級(jí)別。

許多數(shù)據(jù)庫,例如Oracle9i,提供了其他事務(wù)級(jí)別支持。這些級(jí)別不提供"真正的"事務(wù),因?yàn)樗鼈儾煌耆螦CID屬性。然而,它們通過可接受的事務(wù)功能提供更好的性能,因此它們對很多操作類型是非常有用的。

在JDBC中定義的級(jí)別包括:

TRANSACTION_NONE。正式地講,TRANSACTION_NONE不是一個(gè)有效的事務(wù)級(jí)別。根據(jù)java.sql Connection API文件,這個(gè)級(jí)別表示事務(wù)是不被支持的,因此理論上說你不能使用TRANSACTION_NONE作為一個(gè)自變量賦給Connection.setTransactionIsolation()方法。事實(shí)上,雖然一些數(shù)據(jù)庫實(shí)施了這個(gè)事務(wù)級(jí)別,但是Oracle9i卻沒有實(shí)施。

TRANSACTION_READ_UNCOMMITTED。這是最快的完全有效的事務(wù)級(jí)別。它允許你讀取其他還沒有被提交到數(shù)據(jù)庫的并發(fā)事務(wù)做出的修改。這個(gè)API文件指出,臟讀取(dirty reads)、不可重復(fù)讀取(non-repeatable reads)和錯(cuò)誤讀取(phantom reads)都可以在這個(gè)事務(wù)級(jí)別發(fā)生(參閱" 一些非ACID事務(wù)問題 "部分)。這個(gè)級(jí)別意在支持ACID的"原子性(Atomic)"部分,在這個(gè)級(jí)別中,你的修改如果被提交,將被認(rèn)為是同時(shí)發(fā)生的;如果被撤銷,就被當(dāng)作什么也沒發(fā)生。Oracle9i不支持這個(gè)級(jí)別。

TRANSACTION_READ_UNCOMMITTED。這是最快的完全有效的事務(wù)級(jí)別。它允許你讀取其他還沒有被提交到數(shù)據(jù)庫的并發(fā)事務(wù)做出的修改。這個(gè)API文件指出,臟讀取(dirty reads)、不可重復(fù)讀取(non-repeatable reads)和錯(cuò)誤讀取(phantom reads)都可以在這個(gè)事務(wù)級(jí)別發(fā)生(參閱" 一些非ACID事務(wù)問題 "部分)。 這個(gè)級(jí)別意在支持ACID的"原子性(Atomic)"部分,在這個(gè)級(jí)別中,你的修改如果被提交,將被認(rèn)為是同時(shí)發(fā)生的;如果被撤銷,就被當(dāng)作什么也沒發(fā)生。Oracle9i不支持這個(gè)級(jí)別。

TRANSACTION_READ_COMMITTED。這是繼TRANSACTION_READ_UNCOMMITTED之后最快的完全有效的級(jí)別。在此級(jí)別中,你可以讀取已經(jīng)被提交到數(shù)據(jù)庫中的其他并發(fā)事務(wù)所做出的修改。API文件指出,臟讀取在這個(gè)級(jí)別中是被禁止的,但是不可重復(fù)讀取和錯(cuò)誤讀取都可以發(fā)生。這個(gè)級(jí)別是Oracle9i默認(rèn)的級(jí)別。

TRANSACTION_REPEATABLE_READ。這個(gè)級(jí)別比TRANSACTION_SERIALIZABLE快,但是比其他的事務(wù)級(jí)別要慢。讀取操作可以重復(fù)進(jìn)行,這意味著兩次讀取同樣的域應(yīng)該總是得到同樣的值,除非事務(wù)本身改變了這個(gè)值。API文件指出,臟讀取和不可重復(fù)讀取在這個(gè)事務(wù)級(jí)別中是被禁止的,但是錯(cuò)誤讀取可以發(fā)生。

從技術(shù)上講,數(shù)據(jù)庫通過在被讀取或?qū)懭氲男猩霞渔i來實(shí)施這個(gè)級(jí)別,并且保持鎖定狀態(tài)直到事務(wù)結(jié)束。這就防止了這些行被修改或刪除,但是不能防止額外的行被添加--因此,就可能產(chǎn)生錯(cuò)誤讀取。Oracle9i不支持這個(gè)級(jí)別。

TRANSACTION_SERIALIZABLE。這是最慢的事務(wù)級(jí)別,但是它完全與ACID兼容。"單詞可串行化(serializable)"指的就是ACID兼容,其中你的事務(wù)被認(rèn)為在整體上已經(jīng)發(fā)生,就如同其他所有已提交的事務(wù)在這個(gè)事務(wù)之前或之后全部發(fā)生。換句話說,事務(wù)被串行執(zhí)行。

ACID事務(wù)屬性

ACID指的時(shí)數(shù)據(jù)庫事務(wù)的基本屬性:原子性,一致性,隔離性和持續(xù)性。所有的Oracle事務(wù)全部符合這些屬性,雖然你可以在數(shù)據(jù)庫系統(tǒng)中進(jìn)行手動(dòng)設(shè)置級(jí)別來加強(qiáng)各個(gè)屬性(參閱"事務(wù)隔離級(jí)別"部分)。

原子性指的是事務(wù)中的整個(gè)活動(dòng)序列必須被全部完成或全部放棄。事務(wù)不能部分地完成。與隔離性相結(jié)合后(見表1),原子性指的是任意一個(gè)事務(wù)將查看任何其他同時(shí)或以原子形式發(fā)生的事務(wù)所采取的所有活動(dòng)。

一致性指的是事務(wù)既可以建立一個(gè)新的、有效的數(shù)據(jù)狀態(tài)(在這種狀態(tài)中可以進(jìn)行所有的改動(dòng)),它可以在操作失敗的情況下,把所有的數(shù)據(jù)返回到事務(wù)發(fā)生之前已有的狀態(tài)。

隔離性指在一個(gè)事務(wù)中發(fā)生的所有活動(dòng)對其他事務(wù)來說都是不可見的,直到該事務(wù)被提交。

持續(xù)性指的是事務(wù)成功做出并提交的所有改動(dòng)是不變的,并且必須克服系統(tǒng)故障。比如說,如果發(fā)生了故障或者系統(tǒng)重新啟動(dòng),數(shù)據(jù)在最后提交事務(wù)之后所存在的狀態(tài)下是可用的。

臟讀取、不可重復(fù)讀取和錯(cuò)誤讀取在TRANSACTION_SERIALIZABLE級(jí)別是全部被禁止的。從技術(shù)上講,數(shù)據(jù)庫通過鎖定在事務(wù)中使用的表來實(shí)施這個(gè)級(jí)別。Oracle9i支持這個(gè)級(jí)別(正如每個(gè)與符合ACID的數(shù)據(jù)庫那樣)。

開發(fā)通過ACID測試的應(yīng)用程序

選擇正確的級(jí)別

你可以通過使用Connection.setTransactionIsolation()方法設(shè)定一個(gè)連接的事務(wù)級(jí)別。類似地,你可以通過使用Connection.getTransactionIsolation()方法獲得連接的當(dāng)前事務(wù)級(jí)別。你可以通過使用DatabaseMetaData.supportsTransaction IsolationLevel()方法確定由你的數(shù)據(jù)庫驅(qū)動(dòng)程序所支持的事務(wù)級(jí)別,如 清單3 所示。

事務(wù)級(jí)別越高,數(shù)量越多、限制性更強(qiáng)的鎖就會(huì)被運(yùn)用到數(shù)據(jù)庫記錄或者表中。同時(shí),更多的鎖被運(yùn)用到數(shù)據(jù)庫和它們的覆蓋面越寬,任意兩個(gè)事務(wù)沖突的可能性就越大。

如果有一個(gè)沖突(例如兩個(gè)事務(wù)試圖獲取同一個(gè)鎖),第一個(gè)事務(wù)必將會(huì)成功,然而第二個(gè)事務(wù)將被阻止直到第一個(gè)事務(wù)釋放該鎖(或者是嘗試獲取該鎖的行為超時(shí)導(dǎo)致操作失敗)。

更多的沖突發(fā)生時(shí),事務(wù)的執(zhí)行速度將會(huì)變慢,因?yàn)樗鼈儗⒒ㄙM(fèi)更多的時(shí)間用于解決沖突(等待鎖被釋放)。

最大限度地增加應(yīng)用程序的可伸縮性需要平衡地理解事務(wù)執(zhí)行方法。一方面,你可以通過將在事務(wù)中所執(zhí)行的操作數(shù)量減到最少來優(yōu)化應(yīng)用程序,從而減少了單個(gè)事務(wù)所花費(fèi)的時(shí)間。但是這樣就增加了事務(wù)的總數(shù)量,這可能增加沖突的風(fēng)險(xiǎn)。使用批量操作,你可以最大限度地減少所執(zhí)行事務(wù)的數(shù)量。

然而,這增加了單個(gè)事務(wù)的長度,也可能增加沖突的風(fēng)險(xiǎn)。在任意一種情況下,當(dāng)你降低事務(wù)隔離級(jí)別時(shí),事務(wù)使用的鎖就越少,因此越不會(huì)引起性能的下降。這樣做的風(fēng)險(xiǎn)是因?yàn)闆]有使用完全符合ACID的事務(wù),從而損失了功能性。

如果你需要把事務(wù)執(zhí)行時(shí)間減到最少的話,在你的整個(gè)應(yīng)用程序中使用一個(gè)事務(wù)級(jí)別好像并不是很理想。在應(yīng)用程序中查找讀取查詢,對于每個(gè)查詢,考慮在下面" 一些非ACID事務(wù)問題 "部分列出的任何問題是否會(huì)對給定數(shù)據(jù)的查詢或數(shù)據(jù)更新模式產(chǎn)生負(fù)面影響。讀取靜態(tài)表,或者只被讀取它們的同一事務(wù)所更新的表,可以安全地使用最低的事務(wù)級(jí)別。在那些不可能進(jìn)行并發(fā)更新的事務(wù)中,你可以安全、高效地使用諸如TRANSACTION_ READ_COMMITTED這樣的級(jí)別。

一些非ACID事務(wù)問題

當(dāng)一個(gè)連接使用了不完全符合ACID的TRANSATION_SERIALIZABLE事務(wù)級(jí)別時(shí),就會(huì)發(fā)生很多問題。下面的例子使用了一個(gè)名為table_sizes的表,它有兩個(gè)字段,tablename和tablesize。這個(gè)例子還使用了兩個(gè)事務(wù),T1和T2,其中T1使用TRANSACTION_SERIALIZABLE級(jí)別。

臟讀取。當(dāng)一個(gè)事務(wù)能發(fā)現(xiàn)一行中有未提交的更改時(shí),就發(fā)生了一次臟讀取。如果另一個(gè)事務(wù)改變了一個(gè)值,你的事務(wù)可以讀取那個(gè)改變的值,但其他的事務(wù)將回滾其事務(wù),使這個(gè)值無效或成為臟值。例如,這里給出了當(dāng)T2使用事務(wù)級(jí)別TRANSACTION_ READ_UNCOMMITTED時(shí)發(fā)生的情況,其中記錄為tablename=users,tablesize=11。

表1:每個(gè)事務(wù)問題在每個(gè)允許的事務(wù)隔離級(jí)別中發(fā)生的可能性。
隔離級(jí)別 臟讀取 不可重復(fù)讀取 錯(cuò)誤插入
讀取未提交數(shù)據(jù)
讀取已提交數(shù)據(jù)
可重復(fù)讀取
可串行化

1. T1和T2啟動(dòng)它們的事務(wù)。
2. T1將記錄更新為tablename=users,tablesize=12。
3. T2讀取T1未提交的修改,讀取記錄tablename=user,tablesize=12,因?yàn)門2的事務(wù)級(jí)別意味著未提交的修改有時(shí)可以被讀取。
4. T1回滾事務(wù),因此tablename=users行中tablesize=11。
5. T2仍有無效的記錄值:記錄tablename=users,tablesize=12。但是它可以通過臟表尺寸值工作,并且能在臟值的基礎(chǔ)上成功地提交修改。

不可重復(fù)讀取。當(dāng)事務(wù)內(nèi)一條記錄在事務(wù)被兩次讀取而沒有更新時(shí),就發(fā)生了不可重復(fù)讀取,而且,從兩次讀取中可以看到不同的結(jié)果。如果你的事務(wù)讀取一個(gè)值,并且另一事務(wù)提交了對這個(gè)值的一次修改(或刪除了這條記錄),然后你的事務(wù)便可以讀取這個(gè)修改后的值(或發(fā)現(xiàn)這條記錄丟失),盡管你的事務(wù)還沒有提交或回滾。例如,這里給出了當(dāng)T2使用事務(wù)級(jí)別TRANSACTION_READ_COMMITTED時(shí)發(fā)生的情況,其中記錄為tablename=users,tablesize=11。

1. T1和T2啟動(dòng)它們的事務(wù)。
2. T2讀取記錄tablename=users,tablesize=11。
3. T1將記錄更新為tablename=users,tablesize=12并提交修改。
4. T2重新讀取記錄tablename=users,并且現(xiàn)在看到tablesize=12,因?yàn)門2的事務(wù)級(jí)別意味著其他事務(wù)提交的修改可以被看到,盡管T2還沒有提交或回滾。

錯(cuò)誤讀取。當(dāng)一個(gè)事務(wù)讀取由另一個(gè)未提交的事務(wù)插入的一行時(shí),就發(fā)生了錯(cuò)誤讀取。如果另一事務(wù)將一行插入到一個(gè)表里,當(dāng)你的事務(wù)查詢那個(gè)表時(shí)就能夠讀取那條新記錄,即使其他的事務(wù)相繼回滾。例如,這里給出了當(dāng)T2使用事務(wù)級(jí)別TRANSACTION_REPEATABLE_READ時(shí)發(fā)生的情況,其中記錄為tablename=users,tablesize=11。

1. T1和T2啟動(dòng)它們的事務(wù)。
2. T2執(zhí)行SELECT * FROM table_sizes WHERE tablesize>10并讀取一行,tablesize=11的行tablename=user。
3. T1插入tablename=groups,tablesize=28的記錄。
4. T2再次執(zhí)行SELECT * FROM table_sizes WHERE tablesize>10并讀取兩條記錄: tablename=users,tablesize=11和tablename=groups,tablesize=28。
5. T1回滾事務(wù),因此記錄tablename=goups,tablesize=28不再存在于table_sizes表中。

根據(jù)T2被讀取的數(shù)據(jù)集中所具有的一條額外錯(cuò)誤記錄,T2可以成功地提交數(shù)據(jù)。

表1 中,你會(huì)發(fā)現(xiàn)在每一個(gè)所允許的事件隔離級(jí)別中發(fā)生事務(wù)問題的可能性列表。

用戶控制的事務(wù)

在許多應(yīng)用程序中,用戶在一個(gè)事務(wù)結(jié)束以前,必須執(zhí)行一個(gè)明確的動(dòng)作(比如點(diǎn)擊"確定"或"取消")。這些情況會(huì)導(dǎo)致很多問題。例如,如果用戶忘記了終止活動(dòng)或者讓活動(dòng)保持未完成的狀態(tài),資源就一直在應(yīng)用程序和數(shù)據(jù)庫中保持開放狀態(tài),這可能會(huì)在并發(fā)的活動(dòng)和鎖定的資源之間產(chǎn)生沖突,降低了系統(tǒng)的性能。只有單一的用戶應(yīng)用程序或用戶不共享資源的應(yīng)用程序,才不受這個(gè)問題的影響。

讓用戶處于一個(gè)JDBC事務(wù)控制下的主要解決方法是使用優(yōu)化的事務(wù)。這些事務(wù)為外部的JDBC事務(wù)更新收集信息,然后使用一種機(jī)制來檢查更新沒有與其他任一個(gè)可能在兩者間已經(jīng)被處理的更新發(fā)生沖突。

檢查優(yōu)化沖突的機(jī)制包括使用時(shí)間標(biāo)記或更改計(jì)數(shù)器,從期望狀態(tài)檢查區(qū)別。例如,當(dāng)應(yīng)用程序從用戶輸入收集用于更新的數(shù)據(jù)時(shí),數(shù)據(jù)可以作為一批包含時(shí)間標(biāo)記的安全機(jī)制的SQL語句,被發(fā)送到數(shù)據(jù)庫,以確保數(shù)據(jù)庫中的原始數(shù)據(jù)與最初用于客戶應(yīng)用程序的數(shù)據(jù)相同。一個(gè)成功的事務(wù)更新記錄,包括時(shí)間標(biāo)記,顯示了最近修改的數(shù)據(jù)。如果來自另一用戶的更新使第一個(gè)用戶的修改失效,那么時(shí)間標(biāo)記就會(huì)改變,并且當(dāng)前事務(wù)將需要被回滾而不是被提交。對于許多應(yīng)用程序,中等程度的沖突事務(wù)是很少的,因此事務(wù)經(jīng)常會(huì)成功完成。

當(dāng)一個(gè)事務(wù)失敗時(shí),應(yīng)用程序把所輸入的數(shù)據(jù)提交給用戶,使用戶能夠根據(jù)導(dǎo)致沖突的更改,做出必要的修改并且重新提交。

其他方面的考慮

將來,使用JDBC3.0特性的開發(fā)人員將在更多的方法來優(yōu)化事務(wù)。例如,Oracle9i第2版實(shí)施了幾個(gè)JDBC3.0特性,包括事務(wù)存儲(chǔ)點(diǎn)(Savepoint)。存儲(chǔ)點(diǎn)讓你在一個(gè)事務(wù)中標(biāo)記一個(gè)點(diǎn)并且回滾它,而不是回滾整個(gè)事務(wù)。

雖然這聽起來有些難以置信,但存儲(chǔ)點(diǎn)確實(shí)能夠極大地減少性能開銷。它們對性能的實(shí)際影響將證明JDBC3.0會(huì)得到更廣泛的支持,但不要過多使用存儲(chǔ)點(diǎn)或者避免在任何關(guān)鍵性能代碼部分將它們放在一起。如果你確實(shí)要使用它們,就必須確保盡可能地使用Connection.release Savepoint(Savepoint)方法釋放它們的資源。

當(dāng)前,JDBC2.0支持跨越多個(gè)連接的分布式事務(wù),并且Oracle提供了一個(gè)為分布式事務(wù)設(shè)計(jì)的符合業(yè)界XA規(guī)范的Java Transaction API(JTA)模塊。為分布式事務(wù)實(shí)施一個(gè)外部事務(wù)管理器的決定并不是一件小事情,然而,分布式事務(wù)比普通事務(wù)明顯要慢,因?yàn)樗枰~外的通訊工作來協(xié)調(diào)多個(gè)數(shù)據(jù)庫資源之間的連接。從純粹的性能觀點(diǎn)來看,最好是在轉(zhuǎn)移到分布式事務(wù)體系結(jié)構(gòu)以前考慮多種可選擇的設(shè)計(jì)方案。

Jack Shirazi (jack@JavaPerformanceTuning.com)是 JavaPerformanceTuning.com (一個(gè)關(guān)于Java應(yīng)用程序性能調(diào)優(yōu)的所有方面信息的首家資源站點(diǎn))的主管,也是《Java Performance Tuning》(O'Reilly and Associates出版)一書的作者。