從MySQL預設事務隔離級別(RR)到InnoDB非鎖定一致性讀
說到資料庫的隔離級別,我想大家都能說出一二,但是很多時候都是從網上看來的,很多都點到為止不夠詳細,並且沒有經過實踐的檢驗,所以有時候我們會發現有些東西並沒有按照我們預期的來工作,這裡就是一個例子。
MySQL目前流行的版本預設的事務隔離級別一般是可重複讀,一般我們理解在這個隔離級別下,我們新建兩個事務A和事務B,事務A的修改是不影響事務B的,也就是說A事務修改資料後,B事務讀到的資料是不變的,也就是可重複讀,同時在next-key鎖的作用下,又解決了幻讀。不過這裡有一個問題就是B事務讀到的資料是什麼時候的資料?這句話隱藏著一個操作,就是在事務A提交前,事務B已經進行過一次查詢,否則,事務B會讀取最新的資料,因為事務是在begin後第一次select等操作時才開啟的。文字描述的可能不太好理解,所以,直接通過操作的截圖來理解這一過程。
首先是兩個場景
+------+------+------+------+
| id | name | addr | fk |
+------+------+------+------+
| 2 | ss1 | 111 | 2 |
| 5 | ss2 | 111 | 3 |
| 6 | ss3 | 111 | 4 |
| 999 | ss4 | 111 | 5 |
| 1000 | ss5 | 111 | 6 |
| 1008 | ssx | 111 | 100 |
| 1014 | xx | 111 | 7 |
| 1015 | xx | 111 | 8 |
| 1012 | xx | 111 | 101 |
| 1013 | xx | 111 | 101 |
| 888 | xxx | 111 | 7 |
| 1 | yy | 111 | 9 |
+------+------+------+------+
圖1中左邊事務A,右邊事務B,在此情況下,我們稱事務B是可重複讀的,因為兩次讀的結果是一樣的,注意事務B讀取的值是事務A修改後的值。
圖1
那我們再來看一下圖2,在已經執行begin的前提下,事務B讀到的是事務A修改後的值。
圖2
這是為什麼呢?按照我們通常的理解,事務A的提交應該對事務B沒有影響才對,怕不是我們對可重複有什麼誤解?
先來看這樣一個操作,查詢當前事務的trx_id
SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();那麼我們來嘗試一下
可以看到,在執行begin後並沒有生成TRX_ID,也就是說此時事務還沒有開始,根據此篇文章http://www.cnblogs.com/su-han/p/begin.html的說法,只有在執行了select或者以start transaction with consistent snapshot開始事務,才能夠正式開啟事務。這個過程涉及到了非鎖定一致性讀,也就是在事務第一次讀取的時候生成了一個快照,在RR隔離級別下,該快照是事務開始時的資料,也即是產生了TRX_ID之後。更多關於非鎖定一致性讀和鎖定一致性讀可參考https://www.linuxidc.com/Linux/2017-08/146216.htm
參考文獻:[1] https://www.cnblogs.com/Mr-Dawei/p/7460909.html?utm_source=debugrun&utm_medium=referral
[2] http://www.cnblogs.com/su-han/p/begin.html
[3] https://blog.csdn.net/skiof007/article/details/53376751
[4] https://blog.csdn.net/zyz511919766/article/details/49451255
[5] https://www.linuxidc.com/Linux/2017-08/146216.htm