零、概覽
當我們談論隔離級別的時候,我們在談論什麼?看官網的innodb engine的文檔目錄(本文涉及的內容主要是InnoDB Multi-Versioning和InnoDB Locking and Transaction Model兩個章節),談隔離級別的時候,主要談不同隔離級別下的讀寫問題。
隔離性描繪的是當前事務能夠看到其他事務的中間狀態的能力,這個能力通過設置當前事務的隔離級別來描繪。不同level的隔離級別描繪的隔離能力是不同的,本質是不同的隔離級別在讀時走MVCC建立和讀取快照read view的策略不同、寫時加鎖的策略也不同。
所以MySQL官網文檔中給出了兩種讀——一致性讀(普通select一致性讀在不同的隔離級別下走MVCC的策略)和鎖定讀(select for share、select for update和update、delete鎖定讀在不同的隔離級別下寫數據記錄的加鎖策略)。
一、本文要討論的內容
所以本文要討論的讀(一致性讀)和寫(鎖定讀、update、delete)內容範圍如下:
- 讀:Consistent reads 一致性讀(consistent non-lock read一致性非鎖定讀簡稱),也就是不同隔離級別下的MVCC策略
- RC:讀不加鎖寫加鎖,select的時候讀線程不會被其他寫線程加鎖阻塞,所以在RC隔離級別下select防髒讀,要討論讀什麼時候讀取最新的記錄、什麼時候應該去讀回滾段版本鏈最新版本數據
- RR:讀不加鎖寫加鎖,select的時候讀線程不會被其他寫線程加鎖阻塞,所以在RR隔離級別下做到防髒讀、防不可重複讀和防虛讀,要討論什麼時候可以讀最新的記錄,什麼時候讀取回滾段版本鏈的記錄,以及怎麼選擇版本鏈數據記錄的版本
- 兩個核心知識點:回滾段中由undo log組成的版本鏈和快照read view
- 寫:locking reads 和 update、delete,也就是不同隔離級別下寫加鎖的策略。談隔離級別爲什麼要討論寫呢?
- RC:RC可以讀到已提交的事務,也就意味着在同一個事務中多次update、delete、select for share、select for update影響的記錄不會包括正在活動的未提交事務,對於其他未提交的事務,會對其當前正在操作的記錄的索引加寫鎖,當前事務鎖定讀或寫會被阻塞等待,防止了讀到未提交;已提交的事務不加鎖,所以可以讀到已提交的事務結果
- RR:RR除了防讀未提交,還可重複讀和防虛讀,也就意味着在同一個事務中多次update、delete、select for share、select for update影響的記錄應該保持一致,這個一致不僅僅是影響的記錄相同、不能增減記錄,還包括記錄的數據沒被其他事務修改,這也是在《MySQL隔離級別之加鎖策略篇》要分析的內容
- 例如update table_name set name='new name' where id>10,id是主鍵,同一個事務中第一次update影響的記錄集合是{11,15,17},RR下第二次同樣的update也只能影響{11,15,17}的記錄集,否則就破壞了RR的性質。怎麼做到的,《MySQL隔離級別之加鎖策略篇》再展開分析
- 兩個核心知識點:鎖(記錄鎖、gap lock、next-key lock)和不同隔離級別的加鎖策略
二、文章結構概覽和說明
本文要討論的的兩個核心觀點:
- 核心觀點一:討論隔離性就是討論不同隔離級別下的讀寫問題
- 核心觀點二:讀(MVCC)和寫(加鎖策略)
- 讀:討論隔離性的讀就是討論不同隔離級別下的MVCC策略
- 寫:討論隔離性的寫就是討論不同隔離級別下鎖定讀和寫的加鎖策略
爲了要說清楚MySQL事務中的隔離性,對於本文要討論的隔離性的兩個核心觀點並非無中生有,更不是胡編亂造,在MySQL官網文檔中就已經明確提出來了。本文兩個核心觀點的官網內容,參見本文第三部分“隔離性讀寫的官網版本”和第四部分“讀(MVCC)和寫(加鎖策略)的官網版本”。更多本文涉及的官網文檔資料,參見第五部分“官網資料”,更多討論,歡迎留言!
要討論清楚MySQL隔離性,就要討論清楚不同隔離級別下讀的MVCC策略和寫時的加鎖策略。
本文只是MySQL隔離性的開頭,講清楚要討論的內容範圍,然後再分開討論清楚,後續目錄安排如下:
-
《MySQL隔離性之MVCC篇》(核心知識點:版本鏈和快照read view)
-
《MySQL隔離性之加鎖策略篇》(核心知識點:鎖和加鎖策略)
三、隔離性讀寫的官網版本
對於本文觀點“討論隔離性就是討論不同隔離級別下的讀寫問題”這一說法,並非無中生有,更不是胡編亂造,在MySQL官網文檔就已經明確提出來了(官網地址:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html):
3.1 RR
- 讀:Consistent reads within the same transaction read the snapshot established by the first read. This means that if you issue several plain (nonlocking) SELECT statements within the same transaction, these SELECT statements are consistent also with respect to each other.
- 寫:For locking reads (SELECT with FOR UPDATE or FOR SHARE), UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition.
- For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.
- For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range.
3.2 RC
- 讀:Each consistent read, even within the same transaction, sets and reads its own fresh snapshot.
- 寫:For locking reads (SELECT with FOR UPDATE or FOR SHARE), UPDATE statements, and DELETE statements, InnoDB locks only index records, not the gaps before them, and thus permits the free insertion of new records next to locked records. Gap locking is only used for foreign-key constraint checking and duplicate-key checking.
2.3 RU和serializable
RU和Serializable在後續文章中在給出
四、讀(MVCC)和寫(加鎖策略)的官網版本
本文中讀和寫的觀點:
- 讀:Consistent reads 一致性讀(consistent non-lock read一致性非鎖定讀簡稱),也就是不同隔離級別下的MVCC策略
- 寫:locking reads 和 update、delete,也就是不同隔離級別下寫加鎖的策略
對於本文中討論隔離性的讀(MVCC)和寫(加鎖策略)的觀點也並非無衆生有,更不是胡編亂造,在MySQL官網文檔中就已經明確提出來了:
讀的觀點:討論隔離性的讀就是討論不同隔離級別下的MVCC策略
- 隔離級別和一致性讀的關係參見本文第二部分摘抄自MySQL官網文擋“讀”部分的內容
- 一致性讀和MVCC的關係:A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time.
- consistent reads:https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html
- multi-versioning :https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html
- 查看MySQL MVCC的詞條更直觀:This technique lets
InnoDB
transactions with certain isolation levels perform consistent read operations; that is, to query rows that are being updated by other transactions, and see the values from before those updates occurred. 官網此條地址:https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_mvcc
寫的觀點:討論隔離性的寫就是討論不同隔離級別下鎖定讀和寫的加鎖策略
- 隔離級別和加鎖策略的關係參見本文第二部分摘抄自MySQL官網文檔“寫”部分的內容
- locking reads:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html
- innodb locking:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html
五、官網資料
官方文檔鏈接地址:
- 隔離級別:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
- MVCC
- 多版本(回滾段中undo log版本鏈的結構):https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html
- 一致性讀(RC和RR下的read view策略):https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html
- MVCC的目的:對於不同隔離級別,提供不同程度的讀寫併發和一致性
- 鎖和鎖定讀
- 鎖:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html
- 鎖定讀:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html
- 不同隔離級別下的加鎖策略:參看上面【隔離級別】詞條的鏈接
- 加鎖的目的:事務能夠按照不同隔離級別的要求正確併發,對於RR也就是事務中多次加鎖讀的結果要保持一致,也就意味着事務中同一個update、delete和加鎖讀語句多次執行通過加鎖讀看到的結果都是一樣的
- bug
- 事務的鎖定讀將當前事務之後完成的記錄的較大的tx_id修改爲當前事務tx_id,然後再通過MVCC就能看到更多的記錄,因爲本來應該大於read view中最大tx_id的事務的id被修改成了當前事務的tx_id。
- 簡單來說:鎖定讀修改了記錄的trx_id,導致一致性讀走MVCC的時候破壞了RR的性質
- 參見該文最後部分示例:https://my.oschina.net/alchemystar/blog/1927425
- 本文涉及的官網文擋的兩個章節