差點掉坑,MySQL一致性讀原來是有條件的
阿新 • • 發佈:2019-01-06
lock mysql block 影響 val creat read 原因 upd
的更新語句執行完就已經提交了,從結果可以看到普通的
眾所周知,在設定了隔離等級為Repeatable Read
及以上時,InnoDB
可以實現數據的一致性讀。換句話來說,就是事務執行的任意時刻,讀取到的數據是同一個快照,不會受到其他事務的更新影響。
以前一直以為在事務內讀到的數據不會受其他事務影響,後來發現只有普通的select
語句才是一致性讀。如果是update, delete, select for update, select in share mode
等語句是當前讀,讀的是數據庫最新數據, 下面是兩個例子。
加鎖讀
創建一個測試用的表, 然後插入一條測試用的數據
create table test_innodb_read( id int not null primary key, value int ) engine = InnoDB charset=utf8; insert into test_innodb_read values (1, 1);
當前autocommit
和隔離等級如下
db83-3306>>select @@autocommit; +--------------+ | @@autocommit | +--------------+ | 1 | +--------------+ 1 row in set (0.00 sec) db83-3306>>select @@transaction_isolation; +-------------------------+ | @@transaction_isolation | +-------------------------+ | REPEATABLE-READ | +-------------------------+ 1 row in set (0.00 sec)
然後開啟兩個 Session
,分別執行以下操作
時間點 | SessionA | 結果 | SessionB |
---|---|---|---|
1 |
begin select * from test_innodb_read where id=1
|
1 | |
2 | update test_innodb_read set value = 2 where id=1 |
||
3 | select * from test_innodb_read where id=1 |
1 | |
4 | select * from test_innodb_read where id=1 lock in share mode |
2 |
由於設置了自動提交,所以SessionB
Select
不受其他事務影響,所以讀到的數據都是同一版本,而在加鎖讀的情況下采取的是讀最新的數據,所以讀到的數據是最新提交的數據。
DML 操作
在進行數據變更操作的時候,也會拿到最新的數據,用的還是上面的表,插入一條測試數據
insert into test_innodb_read values (2, 1);
然後開啟兩個 Session
,分別執行以下操作,
時間點 | SessionA | 結果 | SessionB |
---|---|---|---|
1 |
begin select * from test_innodb_read where id=2
|
1 | |
2 | update test_innodb_read set value = 2 where id=2 |
||
3 | select * from test_innodb_read where id=2 |
1 | |
4 | update test_innodb_read set value=value+1 where id=2 |
||
5 | select * from test_innodb_read where id=2 |
3 |
SessionA
在時間點 5 查看數據拿到的是 3 而不是 2,原因是,事務在對數據進行更新操作時(時間點4),會先讀取一次數據,這次讀取的不是事務開始版本,而是數據的最新提交的值 2。如果不讀取最新數據的話,就等於覆蓋了SessionB
的更新,所以讀到的是 2,最後得到的數據是 3。
最後
當我知道這個知識點後,感覺背後一涼,以前寫代碼的時候,喜歡在事務裏先把數據查出來,內存中相加減,再存庫,現在想想這樣做就是BUG
啊,坑...
不得不說,極客時間上面的這個MySQL
課程還是很值的,至少讓我推翻了以前的想法
MySQL實戰45講-8 事務到底是隔離的還是不隔離的
來源:https://segmentfault.com/a/1190000017539522
差點掉坑,MySQL一致性讀原來是有條件的