1樓:SHQHDMR
mysql5.6官方文件原話,RR用next-key locks防止幻讀
By default,InnoDBoperates inREPEATABLE READ
transaction isolation level and with theinnodb_locks_unsafe_for_binlog
system variable disabled. In this case,InnoDBuses next-key locks for searches and index scans, which prevents phantom rows (seeSection 14.7.
4, 「Phantom Rows」).
幻讀,官網的定義就是事務中相同讀語句在不同時間讀到了不一樣的結果,與不可重複讀的定義一樣,但是作用原理不同,幻讀是gap lock缺失導致,不可重複讀是一致性檢視的生成和使用時機導致
不用扯什麼當前讀(select * from t for update;)跟快照讀(select * from t;)的結果不一樣,兩個讀,它們語句都不一樣,比結果有什麼意義
2樓:黃杰
MVCC的機制。快照讀不會產生幻讀。因為ReadView生成後就不會發生變化
每次執行都會讀取最新的記錄。(假設要update一條記錄,但是在另乙個事務中已經delete掉這條資料並且commit了,如果update就會產生衝突,所以在update的時候需要知道最新的資料。)
結論:MVCC的機制會使Select語句的快照讀避免幻讀,但是對於當前讀的操作依然會出現幻讀。
例子:假如A事務正在查詢id<10的所有資料,只存在id為1~7的資料,8、9並不存在,此時B事務向資料庫插入id為8的資料,那麼事務A就會出現幻讀現象,本來是不存在id為8的資料的,但是像出現幻覺一樣讀取到了,這就是幻讀。
解決辦法:加上next-key鎖(也就是行鎖+gap鎖),gap鎖會鎖著id為8、9的兩個位置,阻止事務A讀取資料的時候,事務B向資料庫插入資料,這樣就避免幻讀了。
結論:在快照讀情況下,MySQL通過mvcc來避免幻讀。
在當前讀情況下,MySQL通過next-key來避免幻讀
MVCC原理詳解
InnoDB基於MVCC和next-key鎖解決幻讀問題 - osc_8j0twt2u的個人空間 - OSCHINA - 中文開源技術交流社群
MVCC解決幻讀_我要提問_牛客網
RDD2DAG的回答
3樓:lxyscls
補兩個圖
4樓:light0x00
RR級別產生幻讀,往往都是直接或間接執行了「當前讀」,導致ReadView更新,所以會讀到新的
1.事務A中執行修改
update
user
setcol1
='new_val'
whereid=
1;結果:
QueryOK,
0rows
affected(0
.00sec)
Rows
matched:0
Changed:0
Warnings:0
2.事務B插入一條資料,並提交.
begin
;insert
into
user
values
(null
,'A'
);commit
;3. 事務A中再次執行修改
update
user
setcol1
='new_val'
whereid=
1;結果:
QueryOK,
1rows
affected(0
.00sec)
Rows
matched:1
Changed:1
Warnings:0
問題的本質是因為 update語句的查詢階段相當於select ... for update,這會更新事務A的 ReadView, 從而可以讀到「其他事務已提交的修改」.
5樓:陳廣勝
第一,這個問題取決於我們如何定義「幻象」異常。
早期的資料庫都是單版本的,這個定義沒什麼問題。但是,由於多版本的存在,情形就變得複雜了。RR隔離級別在MVCC實現的資料庫中,一般會被實現成快照(SNAPSHOT),這就可能會產生另一種異常。
由於事務會讀到不同的版本,對於相同區間的查詢,事務可能會錯過某些滿足該條件的併發地插入的記錄,該事務只有在插入這條記錄的事務提交後才能看到這條記錄。進而產生的問題就是,事務本應該讀到的資料,卻沒有被讀到。
例如,assignments表有四列(eid, pid, workdate, hours)。assignments表示的是給employee(eid)分配project(pid),並記錄某個工作日(workdate)的工時(hours)。限制每個工作日工時不超過8小時。
assign表示分配工時的儲存過程,假設eid為1的員工已有兩個project, 工時分別為4,1。有兩個併發的事務T1, T2, 同時執行assign。當T1,T2開始時,對於滿足條件eid = 1 and workdate = '2019.
7.11' 的元組,拿到的是相同的快照,它們都判定插入一條工時為4的元組不會使當日工時大於8。
這個異常不滿足上面對幻讀的定義,然而這個事務排程卻是不正確的。一些文獻把這種異常也稱為幻象(write skew style phantom)[2]。
MVCC資料庫無法避免這種異常。如果要避免這種異常,就必須要提高隔離級別到可序列化。可序列化的實現,在MySQL中是通過對讀加鎖(Gap Lock);在PG中是使用SSI演算法,通過驗證連續的RW依賴檢測是否事務是否可序列化[3]。
第二,MySQL有乙個比較特殊的情形,就是它允許覆蓋更新這種行為(不遵守first commit win rule),這讓它產生了另一種幻像。
如下面的例子,有兩個事務,在RR隔離級別下, select是沒有幻讀的,但select for update卻會產生幻讀。因為select是讀,通過時間戳讀快照,事務2讀不到事務1的寫入。而select for update被認為是寫,是可以更新已提交資料的,所以讀到的是最新版本,事務2可以讀到事務1的寫入。
PostgreSQL是沒有這個現象的。
事務1事務2
mysql> start transactionmysql> start transaction;
Query OK, 0 rows affected (0.00 secQuery OK, 0 rows affected (0.00 secmysql> select * from tEmpty set (0.
00 sec)
mysql> insert into t values(1);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 secno phantommysql> select * from tEmpty set (0.00 secphantommysql> select * from t for updatec11 row in set (0.
00 secupdate committed rowmysql> update t set c=2Query OK, 0 rows affected (0.00 secRows matched: 1 Changed:
0 Warnings: 0mysql> commitQuery OK, 0 rows affected (0.01 sec)
MySQL中inner join 和 cross join 的區別?
MySQL 5.7 文件中的表述 對於 MySQL,JOIN,CROSS JOIN,INNER JOIN 完全等價 one flower 在MySQL中,CROSS JOIN語法上等價於INNER JOIN 它們可以彼此代替。在標準SQL中,它們不等價。INNER JOIN結合ON子句使用 CROS...
python從mysql中取到time型別欄位的值變成timedelta型別了,如何轉換為時間格式?
管理他爹 自問自答,上面回答的答案都是答非所問,最後還是在stackoverflow上找到了答案,正確解決方式如下 value datetime.timedelta 0,64800 datetime.datetime.min value time 青牛 來個例子 usr bin env python...
mysql中資料已經完成了binlog的寫入儲存引擎的提交,那麼資料算是已經落盤了嗎?
趙偉 不一定,要看你的 innodb flush log at trxcommit 和sync binlog 的設定。只有兩者都是1,乙個事務提交後才意味著其改動會持久化。有人為了效能把兩者都設定為0,那意味著一旦mysqld 程序不是正常退出,比如被kill掉,或者crash,即使作業系統保持正常...