本文轉載至 http://blog.csdn.net/turkeyzhou/article/details/5115228
DBC1.0 、JDBC2.0 、JDBC3.0 中分別用以下方法創建Statement 。
JDBC1.0 : createStatement()
JDBC2.0 : createStatement(resultSetType, resultSetConcurrency)
JDBC3.0 : createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)
下面依次分析resultSetType 、resultSetConcurrency 、resultSetHoldability 這幾個參數的含義。
一 ResultSetType
resultSetType 的可選值有: ResultSet.TYPE_FORWARD_ONLY 、ResultSet.TYPE_SCROLL_INSENSITIVE、ResultSet.TYPE_SCROLL_SENSITIVE 。
1 :ResultSet.TYPE_FORWARD_ONLY
默認的cursor 類型,僅僅支持結果集forward ,不支持backforward ,random ,last ,first 等操作。
2 :ResultSet.TYPE_SCROLL_INSENSITIVE
支持結果集backforward ,random ,last ,first 等操作,對其它session 對數據庫中數據做出的更改是不敏感的。
實現方法:從數據庫取出數據后,會把全部數據緩存到cache 中,對結果集的后續操作,是操作的cache 中的數據,數據庫中記錄發生變化后,不影響cache 中的數據,所以ResultSet 對結果集中的數據是INSENSITIVE 的。
3 :ResultSet.TYPE_SCROLL_SENSITIVE
支持結果集backforward ,random ,last ,first 等操作,對其它session 對數據庫中數據做出的更改是敏感的,即其他session 修改了數據庫中的數據,會反應到本結果集中。
實現方法:從數據庫取出數據后,不是把全部數據緩存到cache 中,而是把每條數據的rowid 緩存到cache 中,對結果集后續操作時,是根據rowid 再去數據庫中取數據。所以數據庫中記錄發生變化后,通過ResultSet 取出的記錄是最新的,即ResultSet是SENSITIVE 的。 但insert 和delete 操作不會影響到ResultSet ,因為insert 數據的rowid 不在ResultSet 取出的rowid 中,所以insert的數據對ResultSet 是不可見的,而delete 數據的rowid 依舊在ResultSet 中,所以ResultSet 仍可以取出被刪除的記錄( 因為一般數據庫的刪除是標記刪除,不是真正在數據庫文件中刪除 )。
做個試驗,驗證一下SENSITIVE 特性。數據庫為oracle10g ,驅動為ojdbc14.jar 。
test 表中數據如下:
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) {
- }
- }
- }
- 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 類型,首先執行 sql 訪問數據庫,然后執行 rs.next() 移動游標取數據。在循環里面加上 Thread.sleep (20000) 的目的是為了我們有時間在后台把數據庫里的數據改了。比如當在循環里打印出第一行的數據后,我們在后台,把第三行數據的 c3 列改成 ”3uuu” 。如果 ResultSet 真的是敏感的話,那應該取出 ”3uuu” ,而不是原始的“ 3c3 ”。但最終的結果卻是如下:
[ 行號: 1] 1c1 1c2 1c3
[ 行號: 2] 2c1 2c2 2c3
[ 行號: 3] 3c1 3c2 3c3
數據沒變呀,ResultSet 不敏感啊!於是去查閱資料,找了n 久,還是在英文文檔上找到了答案。原來是fetchsize 的問題。調用ResultSet 的next 方法取數據時,並不是每調用一次方法就去數據庫里查一次,而是有個fetchSize, 一次取fetchSize 條數據。Oracle默認的fetchsize 等於10 ,所以上面的代碼在第一次調用rs.next() 時,就已經把3 條數據都取出來了,所以才會有上面的結果。
第二次實驗,在ResultSet rs = stmt.executeQuery(sql); 前面加上 stmt.setFetchSize(1); 將fetchSize 設置為1 。然后重新第一次實驗的步驟,發現最 終結果為:
[ 行號: 1] 1c1 1c2 1c3
[ 行號: 2] 2c1 2c2 2c3
[ 行號: 3] 3c1 3c2 3uuu
原因就是 fetchsize 設置為 1 時,每次 next 取數時都會重新用 rowid 取數據庫里取數據,當然取到的是最新的數據了。
二 ResultSetConcurrency
ResultSetConcurrency的可選值有2個:
ResultSet.CONCUR_READ_ONLY 在ResultSet中的數據記錄是只讀的,不可以修改
ResultSet.CONCUR_UPDATABLE 在ResultSet中的數據記錄可以任意修改,然后更新到數據庫,可以插入,刪除,修改。
三 ResultSetHoldability
ResultSetHoldability 的可選值有2 個 :
HOLD_CURSORS_OVER_COMMIT: 在事務commit 或rollback 后,ResultSet 仍然可用。
CLOSE_CURSORS_AT_COMMIT: 在事務commit 或rollback 后,ResultSet 被關閉。
需要注意的地方:
1 :Oracle 只支持HOLD_CURSORS_OVER_COMMIT 。
2 :當Statement 執行下一個查詢,生成第二個ResultSet 時,第一個ResultSet 會被關閉,這和是否支持支持HOLD_CURSORS_OVER_COMMIT 無關。
四 驗證數據庫是否支持ResultSet的各種特性
不同的數據庫版本及 JDBC 驅動版本,對 ResultSet 的各種高級特性的支持是不一樣的,我們可以通過以下方法,來驗證具體的數據庫及 JDBC 驅動,是否支持 ResultSet 的各種特性。
DatabaseMetaData dbMeta = conn.getMetaData();
然后調用 DatabaseMetaData 對象的以下方法:
boolean supportsResultSetType(int resultSetType);
boolean supportsResultSetConcurrency(int type, int concurrency);
boolean supportsResultSetHoldability(int holdability);