mysql可重復讀現象及原理分析
一、可重復讀
我們先看看現象,再分析原理。我的mysql版本是5.5。
下面是一張表,只有一條數據,並且我開啟了事物
此時,另一個事物將record加1,因此我在開啟一個命令行客戶端,執行下面的命令:
成功加1之后,實際上,數據庫中record肯定是2。
然后回到之前的客戶端,再查一次:
沒毛病,record還是1,果然是可重復讀。有些人以為mysql的可重復讀是通過行鎖實現的,
從上面可以知道,肯定不是,如果是的話,第一次select * from test的時候,id=1的記錄就會加行鎖,我都加行鎖了,我還沒提交,另外的事物是怎么update成功的。
結論就是mysql使用的MVCC(多版本並發控制),MVCC詳解可以看:https://blog.csdn.net/whoamiyang/article/details/51901888
我們繼續,我之前的第一個事物還沒提交,不過提交之前,我也想加1;
加完之后我再查一下,額,record是3,好像很奇怪,但也不奇怪。
其實,update test set record=record+1 where id=1;這條語句中,在加1之前,他知道自己等於2,然后2+1=3。
也就是說,update時讀取數據是最新版本的數據,而select是到當前事物版本為止的數據。當更新成功之后,當前版本即為最新版本,再次select,讀取的是最新的數據。
在這里討論下樂觀鎖的必要性。下面是樂觀鎖的實現,實現樂觀鎖,我們一般會這么做
update test set record=record+1 where id=1 and record=1;
如果不用樂觀鎖,你用select讀取到的值其實根本不准確。除非你開啟悲觀鎖,像下面這樣:
select * from test where id=1 for update;
這樣可以讀取到最新的內容,同時在你當前的事物提交之前,其他事物的update此條記錄將會鎖等待。
故事到此,還沒有結束,此時我們開啟事物三,也做加1操作看會發生什么。
結果是,鎖等待超時,也就是說(事物一)在更新完后,會加行鎖,這個應該比較好理解。事物中,剛開始查詢的時候是不會加行鎖的,但是當有更新操作之后,會加行鎖,直到事物提交。
因為事務一還沒有提交,所以事務三的select * from test;還只能查詢到事務二提交的結果,也就是record是2
然后因為事務一中對id=1這條數據進行了修改,所以mysql自動將這條數據開啟了行鎖,在事務一提交之前,任何事務不可以修改id=1這條數據
本文轉自:
mysql可重復讀現象及原理分析 - mysql數據庫欄目 - 紅黑聯盟
https://www.2cto.com/database/201807/763885.html