JDBC1.0 、JDBC2.0 、JDBC3.0 中分別用以下方法創(chuàng)建Statement 。
JDBC1.0 : createStatement()
JDBC2.0 : createStatement(resultSetType, resultSetConcurrency)
JDBC3.0 : createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)
下面依次分析resultSetType 、resultSetConcurrency 、resultSetHoldability 這幾個參數(shù)的含義。
一 ResultSetType
resultSetType 的可選值有: ResultSet.TYPE_FORWARD_ONLY 、ResultSet.TYPE_SCROLL_INSENSITIVE 、ResultSet.TYPE_SCROLL_SENSITIVE 。
1 :ResultSet.TYPE_FORWARD_ONLY
默認(rèn)的cursor 類型,僅僅支持結(jié)果集forward ,不支持backforward ,random ,last ,first 等操作。
2 :ResultSet.TYPE_SCROLL_INSENSITIVE
支持結(jié)果集backforward ,random ,last ,first 等操作,對其它session 對數(shù)據(jù)庫中數(shù)據(jù)做出的更改是不敏感的。
實現(xiàn)方法:從數(shù)據(jù)庫取出數(shù)據(jù)后,會把全部數(shù)據(jù)緩存到cache 中,對結(jié)果集的后續(xù)操作,是操作的cache 中的數(shù)據(jù),數(shù)據(jù)庫中記錄發(fā)生變化后,不影響cache 中的數(shù)據(jù),所以ResultSet 對結(jié)果集中的數(shù)據(jù)是INSENSITIVE 的。
3 :ResultSet.TYPE_SCROLL_SENSITIVE
支持結(jié)果集backforward ,random ,last ,first 等操作,對其它session 對數(shù)據(jù)庫中數(shù)據(jù)做出的更改是敏感的,即其他session 修改了數(shù)據(jù)庫中的數(shù)據(jù),會反應(yīng)到本結(jié)果集中。
實現(xiàn)方法:從數(shù)據(jù)庫取出數(shù)據(jù)后,不是把全部數(shù)據(jù)緩存到cache 中,而是把每條數(shù)據(jù)的rowid 緩存到cache 中,對結(jié)果集后續(xù)操作時,是根據(jù)rowid 再去數(shù)據(jù)庫中取數(shù)據(jù)。所以數(shù)據(jù)庫中記錄發(fā)生變化后,通過ResultSet 取出的記錄是最新的,即ResultSet 是SENSITIVE 的。 但insert 和delete 操作不會影響到ResultSet ,因為insert 數(shù)據(jù)的rowid 不在ResultSet 取出的rowid 中,所以insert 的數(shù)據(jù)對ResultSet 是不可見的,而delete 數(shù)據(jù)的rowid 依舊在ResultSet 中,所以ResultSet 仍可以取出被刪除的記錄( 因為一般數(shù)據(jù)庫的刪除是標(biāo)記刪除,不是真正在數(shù)據(jù)庫文件中刪除 )。
做個試驗,驗證一下SENSITIVE 特性。數(shù)據(jù)庫為oracle10g ,驅(qū)動為ojdbc14.jar 。
test 表中數(shù)據(jù)如下:
c1 | c2 | c3 |
1c1 | 1c2 | 1c3 |
2c1 | 2c2 | 2c3 |
3c1 | 3c2 | 3c3 |
程序如下:
public static void testResultSetSensitive(Connection conn) throws Exception{String sql = "SELECT c1,c2,c3 FROM test";try {Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);ResultSet rs = stmt.executeQuery(sql);while (rs.next()) {System.out.println("[行號:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2)+ "\t" + rs.getString(3));Thread.sleep(20000);}rs.close();stmt.close();} catch (SQLException e) {e.printStackTrace();} finally {try {conn.close();} catch (Exception e) {}}}
定義ResultSet 為 ResultSet. TYPE_SCROLL_SENSITIVE 類型,首先執(zhí)行 sql 訪問數(shù)據(jù)庫,然后執(zhí)行 rs.next() 移動游標(biāo)取數(shù)據(jù)。在循環(huán)里面加上 Thread.sleep (20000) 的目的是為了我們有時間在后臺把數(shù)據(jù)庫里的數(shù)據(jù)改了。比如當(dāng)在循環(huán)里打印出第一行的數(shù)據(jù)后,我們在后臺,把第三行數(shù)據(jù)的 c3 列改成 ”3uuu” 。如果 ResultSet 真的是敏感的話,那應(yīng)該取出 ”3uuu” ,而不是原始的“ 3c 3 ”。但最終的結(jié)果卻是如下:
[ 行號: 1] 1c1 1c2 1c3
[ 行號: 2] 2c1 2c2 2c3
[ 行號: 3] 3c1 3c2 3c3
數(shù)據(jù)沒變呀,ResultSet 不敏感啊!于是去查閱資料,找了n 久,還是在英文文檔上找到了答案。原來是fetchsize 的問題。調(diào)用ResultSet 的next 方法取數(shù)據(jù)時,并不是每調(diào)用一次方法就去數(shù)據(jù)庫里查一次,而是有個fetchSize, 一次取fetchSize 條數(shù)據(jù)。Oracle 默認(rèn)的fetchsize 等于10 ,所以上面的代碼在第一次調(diào)用rs.next() 時,就已經(jīng)把3 條數(shù)據(jù)都取出來了,所以才會有上面的結(jié)果。
第二次實驗,在ResultSet rs = stmt.executeQuery(sql); 前面加上 stmt.setFetchSize(1); 將fetchSize 設(shè)置為1 。然后重新第一次實驗的步驟,發(fā)現(xiàn)最 終結(jié)果為:
[ 行號: 1] 1c1 1c2 1c3
[ 行號: 2] 2c1 2c2 2c3
[ 行號: 3] 3c1 3c2 3uuu
原因就是 fetchsize 設(shè)置為 1 時,每次 next 取數(shù)時都會重新用 rowid 取數(shù)據(jù)庫里取數(shù)據(jù),當(dāng)然取到的是最新的數(shù)據(jù)了。
二 ResultSetConcurrency
ResultSetConcurrency的可選值有2個:
ResultSet.CONCUR_READ_ONLY 在ResultSet中的數(shù)據(jù)記錄是只讀的,不可以修改
ResultSet.CONCUR_UPDATABLE 在ResultSet中的數(shù)據(jù)記錄可以任意修改,然后更新到數(shù)據(jù)庫,可以插入,刪除,修改。
三 ResultSetHoldability
HOLD_CURSORS_OVER_COMMIT: 在事務(wù)commit 或rollback 后,ResultSet 仍然可用。
CLOSE_CURSORS_AT_COMMIT: 在事務(wù)commit 或rollback 后,ResultSet 被關(guān)閉。
需要注意的地方:
1 :Oracle 只支持HOLD_CURSORS_OVER_COMMIT 。
2 :當(dāng)Statement 執(zhí)行下一個查詢,生成第二個ResultSet 時,第一個ResultSet 會被關(guān)閉,這和是否支持支持HOLD_CURSORS_OVER_COMMIT 無關(guān)。
四 驗證數(shù)據(jù)庫是否支持ResultSet的各種特性
不同的數(shù)據(jù)庫版本及 JDBC 驅(qū)動版本,對 ResultSet 的各種高級特性的支持是不一樣的,我們可以通過以下方法,來驗證具體的數(shù)據(jù)庫及 JDBC 驅(qū)動,是否支持 ResultSet 的各種特性。
DatabaseMetaData dbMeta = conn.getMetaData();
然后調(diào)用 DatabaseMetaData 對象的以下方法:
boolean supportsResultSetType(int resultSetType);
boolean supportsResultSetConcurrency(int type, int concurrency);
boolean supportsResultSetHoldability(int holdability);
參考的2 篇英文文檔:
http://cs.felk.cvut.cz/10gr2/java.102/b14355/jdbcvers.htm (JDBC Standards Support )
http://download.oracle.com/docs/cd/B10501_01/java.920/a96654/resltset.htm#1023642 (Oracle9i JDBC Developer's Guide and Reference Release 2 (9.2))