ResultSet.CONCUR_UPDATABLE, ResultSet.TYPE_SCROLL_SENSITIVE

 

這個問題我在幾年前說過,但今天再次從CSDN上看到有人問這個問題,可以看出,真正懂這個問題的人1%都不到。
我再次把這個問題寫在這裏,希望光臨我的BLOG的人能真正瞭解它。

我們先來做一個例子,在例子中我用的是mysql-essential-5.1.30-win32版。

來跟我做以下幾個命令:

mysql> create database axman;
mysql> use axman;
mysql> create table axmantest(
    -> id int(4) not null auto_increment primary key
    -> name varchar(20));

mysql> insert into axmantest (name) values ('axman')
mysql> insert into axmantest (name) values ('sager')
mysql> insert into axmantest (name) values ('p4');

OK,寫一個測試程序:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class MainTest {
public static void main(String[] args) throws Exception{
  Class.forName("org.gjt.mm.mysql.Driver");
  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/axman?useUnicode=true&characterEncoding=UTF-8","root","password");
  Statement stmt = conn.createStatement(ResultSet.CONCUR_UPDATABLE, ResultSet.TYPE_SCROLL_SENSITIVE);
  ResultSet rs = stmt.executeQuery("select * from axmantest");
  System.out.println("請刪除!");
  Thread.sleep(1000*20);
  while(rs.next()){
   System.out.println(rs.getString(1)+","+rs.getString(2));
  }
  rs.close();
  stmt.close();
  conn.close();
}
}

先在剛纔的MYSQL命令環境下輸入命令:
select * from axmantest;
+----+-------+
| id | name  |
+----+-------+
|  1 | axman |
|  2 | sager |
|  3 | p4    |
+----+-------+
3 rows in set (0.00 sec)

delete from axmantest where id = 3;不要提交,敲好放在這兒,運行那個測試程序。看到“請刪除”三個字立即切換到
Mysql命令環境下回車。
跟着:
select * from axmantest;
+----+-------+
| id | name  |
+----+-------+
|  1 | axman |
|  2 | sager |
+----+-------+
2 rows in set (0.00 sec)

回到測試程序,看看:
1,axman
2,sager
3,p4

我的個神啦,這哪叫結果集敏感啊?完全是INSENSITIVE嘛!

但是,這正是TYPE_SCROLL_SENSITIVE造成的。

對於TYPE_SCROLL_INSENSITIVE,一次查詢的結果可能存在數據庫端的內存緩衝中,也可以直接發送到JVM的內存中,
如果結果集很小,會直接發送到JVM層,然後被next定位,轉換數據類型,顯示,或者緩存在數據庫內存中。總之
查詢結果已經和數據庫脫離,這時如果數據庫記錄被其它進程更新,則結果集無法得知,還是使用緩存的記錄。

而對於TYPE_SCROLL_SENSITIVE,一次查詢的結果並不是直接的記錄被緩存下來,只是符合條件的記錄的“原始ROWID”
被緩存了,這個原始ROWID並非特指ORACLE的ROWID,而是數據庫底層定位記錄的索引值。簡單說
select * from axmantest操作的結果並不是
1,axman
2,sager
3,p4
這些內容被緩存了。而是類似rd_file_offset_0x111010101001這樣的值被緩存了,然後next定位到這條記錄時,
數據庫會再次根據這個ROWID做底層操作:
select * from axmantest where rowid = rd_file_offset_0x111010101001;
簡單說每next一次都會發生一次查詢,這樣可以保證next後操作到的是當前最新的數據。
對於更新操作,如果你先查詢,然後數據被其它進程更新掉了,然後next到這條記錄時肯定沒有問題,會取出最新的
內容,但對於刪除操作。因爲數據庫刪除記錄只是記錄上做一個標記,不再被檢索,但原來被緩存的ROWID還在,根據
它還可以通過數據庫自己的底層操作正確地把數據提取出來,所以你看到的已經被手工刪除的數據又被顯示出來了。

同樣插入操作因爲查詢的時候結果集中還沒有要插入的操作,所以不可能緩存了它的ROWID,我們再次做這個例子,把
“請刪除”修改成“請插入”(有些不好聽),現在數據庫中是兩條記錄,當運行程序看到“請插入”時立即插入,注意
我說的是往表中插入記錄,不是插入別的。然後看一下運行結果還是兩條記錄。

如果有興趣再試一下更新操作,你會看更新的結果會馬上反映出來。

所以TYPE_SCROLL_SENSITIVE只能更新操作敏感,其它的插入操作和刪除操作不會及時地反映到結果集中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章