本文介紹了可重復讀取隔離級別SELECT VS UPDATE…WHERE的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
也許你可以在這里為我解釋一些事情:
DB=MySQL 5.7
存儲引擎:InnoDB
隔離級別:可重復讀取
下表:
---------------
| MyTable |
---------------
| PK | Concur |
---------------
| 3 | 2 |
---------------
此時我沒有正在進行的事務,我選擇此記錄,如下所示
SELECT * FROM MyTable WHERE PK = 3
并將結果存儲在我的程序中。
我現在啟動一個數據庫事務。
事務開始后,外部進程將PK
=3的記錄的Concur
從2遞增到3。
我尚未再次從事務內的該表中讀取。
我從我的事務內部發出以下查詢:
UPDATE MyTable SET Concur = 3 WHERE PK = 3 AND Concur = 2
這將通過0 records affected
成功。很明顯,它會根據我的事務開始后更改的數據進行評估。
仍在事務中,我隨后查詢:
SELECT * FROM MyTable WHERE PK = 3
它將向我返回PK = 3 and Concur = 2
的記錄,這些值是事務之前的值。
為什么SELECT
和UPDATE ... WHERE
的行為不同,我缺少什么?
我認為UPDATE ... WHERE
語句要么直接失敗,而不是在0條記錄受到影響的情況下成功,要么在那里成功,但有1條記錄受到影響,然后在隨后的COMMIT
處失敗,但不是這種混合和匹配。
這里有什么見解嗎?
推薦答案
https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html
一致讀取意味著InnoDB使用多版本控制向查詢呈現某個時間點的數據庫快照。查詢會看到在該時間點之前提交的事務所做的更改,而不會看到后來或未提交的事務所做的更改。此規則的例外情況是,查詢會看到同一事務中較早的語句所做的更改。此異常會導致以下異常:如果更新表中的某些行,SELECT會看到更新的行的最新版本,但也可能會看到任何行的較舊版本。如果其他會話同時更新同一個表,則異常情況意味著您可能會看到該表處于數據庫中不存在的狀態。
重要的條件是,如果您更改了行,您的一致讀取將被”刷新”,因此它包括您剛剛所做的更改。
但如果您更新,它始終是行的最新版本,而不是事務的一致讀取可以查看的版本。因此,如果另一個事務已經進行了該更改,則您的更新可能不會產生任何凈效果。這就是您觀察到的情況。
因此,您的事務發出了更新,但未更改行。
這可能不是您希望InnoDB的行為方式,但它確實是這樣的。
這篇關于可重復讀取隔離級別SELECT VS UPDATE…WHERE的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,