1、當(dāng)處理多個(gè)訪問相同數(shù)據(jù)的用戶時(shí),通常可能出現(xiàn)三種問題:
臟讀
當(dāng)應(yīng)用程序使用了被另一個(gè)應(yīng)用程序修改過的數(shù)據(jù),而這個(gè)數(shù)據(jù)處于未提交狀態(tài)時(shí),就會(huì)發(fā)生臟讀。第二個(gè)應(yīng)用程序隨后會(huì)請(qǐng)求回滾被其修改的數(shù)據(jù)。第一個(gè)事務(wù)使用的數(shù)據(jù)就會(huì)被損壞,或者“變臟”。
不可重復(fù)的讀
當(dāng)一個(gè)事務(wù)獲得了數(shù)據(jù),而該數(shù)據(jù)隨后被一個(gè)單獨(dú)的事務(wù)所更改時(shí),若第一個(gè)事務(wù)再次讀取更改后的數(shù)據(jù),就會(huì)發(fā)生不可重復(fù)的讀。這樣,第一個(gè)事務(wù)進(jìn)行了一個(gè)不可重復(fù)的讀。
虛讀
當(dāng)事務(wù)通過某種查詢獲取了數(shù)據(jù),另一個(gè)事務(wù)修改了部分該數(shù)據(jù),原來的事務(wù)第二次獲取該數(shù)據(jù)時(shí),就會(huì)發(fā)生虛讀。第一個(gè)事務(wù)現(xiàn)在會(huì)有不同的結(jié)果集,它可能包含虛讀。
2、Java.sql.Connection接口定義的隔離級(jí)別
TRANSACTION_NONE 說明不支持事務(wù)
TRANSACTION_READ_UNCOMMITTED 說明在提交前一個(gè)事務(wù)可以看到另一個(gè)事務(wù)的變化。這樣臟讀、不可重復(fù)的讀和虛讀都是允許的。
TRANSACTION_READ_COMMITTED 說明讀取未提交的數(shù)據(jù)是不允許的。這個(gè)級(jí)別仍然允許不可重復(fù)的讀和虛讀產(chǎn)生。
TRANSACTION_REPEATABLE_READ 說明事務(wù)保證能夠再次讀取相同的數(shù)據(jù)而不會(huì)失敗,但虛讀仍然會(huì)出現(xiàn)。
TRANSACTION_SERIALIZABLE 是最高的事務(wù)級(jí)別,它防止臟讀、不可重復(fù)的讀和虛讀。
3、事務(wù)的隔離級(jí)別
在J2EE中,通過java.sql.Connection接口設(shè)置事務(wù)隔離級(jí)別,這一接口為連接的隔離級(jí)別提供了getter()和setter()
Int getTransactionIsolation() throws SQLException
void setTransactionIsolation() throws SQLException
Connection對(duì)象負(fù)責(zé)事務(wù),一旦收到事務(wù)請(qǐng)求,事務(wù)將自動(dòng)提交,因?yàn)镃onnection對(duì)象已定義為自動(dòng)提交方式,可通過setAutoCommit(false)禁用自動(dòng)提交模式
另外java.sql.DatabaseMetaData接口為數(shù)據(jù)存儲(chǔ)提供支持的隔離級(jí)別查找方法:getTransactionIsolation(),supportsTransactionIsolationLevel()
對(duì)多個(gè)庫操作的分布式事務(wù)必須在所有庫中執(zhí)行同一個(gè)隔離級(jí)別,否則會(huì)出現(xiàn)意想不到的結(jié)果
4、事務(wù)提交和回滾
為了完成提交事務(wù)和回滾事務(wù),JDBC API包括了兩個(gè)方法作為 Connection 接口的一部分。若將 Connection 對(duì)象名稱指定為 con,通過調(diào)用 con.commit(); 可以保存程序狀態(tài);
通過調(diào)用 con.rollback(); 可以返回到以前保存的狀態(tài)。如果數(shù)據(jù)庫實(shí)際運(yùn)行操作時(shí)有錯(cuò)誤發(fā)生,這兩個(gè)方法都會(huì)拋出 SQLExceptions,所以您需要在 try ... catch 塊中包裝它們。
5、批處理和事務(wù)
缺省情況下,JDBC 驅(qū)動(dòng)程序運(yùn)行在被稱為自動(dòng)提交的模式下,可禁用自動(dòng)提交模式
con.setAutoCommit(false);
批處理操作中通過在一次單獨(dú)的操作(或批處理)中執(zhí)行多個(gè)數(shù)據(jù)庫更新操作
{con.setAutoCommit(false) ;
Statement stmt = connection.createStatement() ; stmt.addBatch("INSERT INTO people VALUES('Joe Jackson', 0.325, 25, 105) ; stmt.addBatch("INSERT INTO people
VALUES('Jim Jackson', 0.349, 18, 99) ; stmt.addBatch("INSERT INTO people VALUES('Jack Jackson', 0.295, 15, 84) ;
int[] updateCounts = stmt.executeBatch() ; con.commit() ;