這個問題我在幾年前說過,但今天再次從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只能更新操作敏感,其它的插入操作和刪除操作不會及時地反映到結果集中。