轉自:https://blog.csdn.net/axman/article/details/3984103java
這個問題我在幾年前說過,但今天再次從CSDN上看到有人問這個問題,能夠看出,真正懂這個問題的人1%都不到。
我再次把這個問題寫在這裏,但願光臨個人BLOG的人能真正瞭解它。mysql
咱們先來作一個例子,在例子中我用的是mysql-essential-5.1.30-win32版。sql
來跟我作如下幾個命令:數據庫
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;.net
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.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
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();
}
}code
先在剛纔的MYSQL命令環境下輸入命令:
select * from axmantest;
+----+-------+
| id | name |
+----+-------+
| 1 | axman |
| 2 | sager |
| 3 | p4 |
+----+-------+
3 rows in set (0.00 sec)blog
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只能更新操做敏感,其它的插入操做和刪除操做不會及時地反映到結果集中。