记录一次线上mysql事务隔离级别引发的思考
?場景:我們公司在客戶方(某證券公司)部署了幾套程序,用來監聽客戶方內網kafka消息(kafka消息是我們公司寫入的),一旦監聽到消息便即時消費寫入到相關的表中(一個主表及6個子表),然后客戶部門再同步數據給他們的下游業務部門使用。某天客戶來電說:"需要主表增加一個字段,用來存儲與其相關聯的子表數據,拼成一個json格式存儲在主表字段中",原因是下游部門在使用數據的時候發現:比如,某個時刻A主表關聯子表查詢,子表關聯出了3條記錄,接著在很短的時間間隔內B再次讀取(執行相同的SQL)發現子表關聯出了5條記錄(給我的感覺就是"幻讀"),于是就有了上面客戶提的需求。
當然出現這種現象,可以是我們程序寫入順序及事務的隔離級別引起的,也有可以是客戶同步給下游部門(定時任務同步的)時候,一個一個表來同步的,也有可能會導致這個問題。
接到電話后,首先想到的是我們程序在往mysql插入數據時代碼里顯式的使用了@Transactional事務注解,同時客戶那邊安裝的mysql隔離級別是"讀已提交",插入多個表,一個一個表插入合理;其次,內心是比較抗拒客戶的加字段需求的,因為主表現在1千多萬數據,占用了200多G磁盤空間,加字段非常吃力,而且還得停掉程序(大表加字段,你們懂的)。
于是乎就得回顧一下mysql的事務隔離級別知識了:
?1、mysql的默認隔離級別:
可重復讀
?2、mysql事務的并發問題:
臟讀:事務A讀取了事務B(未提交)更新后的數據,B事務回滾導致事務A讀取到的數據為臟數據
不可重復讀:事務A(未提交)讀取數據,此時事務B(已提交)更新了數據,導致事務A在事務B提交前后多次讀取的結果不一致
幻讀:事務A(未提交)讀取數據,此時事務B(已提交)插入或刪除了某些數據,導致事務A再次讀取時發現數據不一致
幻讀與不可重復讀的現象相似,但是可以看出幻讀側重于insert/delete操作,不可重復讀側重于update操作
?3、mysql事務隔離級別測試:
(一)讀未提交
(1)設置當前事務隔離級別為讀未提交,客戶端A開啟一個事務,然后查詢表初始數據
(2)客戶端A提交事務事前,客戶端B開啟新事務更新了order_info表數據,并且B的事務未提交
(3)在客戶端A上查詢數據,發現讀取到了客戶端B的更新操作
(4)客戶端B設置回滾,客戶端A讀取的便是臟數據了
(5)再次在客戶端A上讀取數據,發現又是未更新前的操作,這個時候程序會使用第四步驟讀到的臟數據……bug就來了
(二)讀已提交
(1)設置當前事務隔離級別為"讀已提交",客戶端A開啟一個事務,然后查詢表初始數據
(2)客戶端A提交事務事前,客戶端B開啟新事務更新了order_info表數據,并且B的事務未提交
(3)在客戶端A上查詢數據,并沒有讀取到客戶端B的更新操作,數據正常
(4)客戶端B提交修改操作的事務
(5)客戶端此時再次讀取數據,讀取到了客戶端B更改的數據,即體現了不可重復讀的含義~
(三)可重復讀
(1)設置當前事務隔離級別為"可重復讀",客戶端A開啟一個事務,然后查詢表初始數據
(2)客戶端A提交事務事前,客戶端B開啟新事務更新了order_info表數據,并且B的事務已提交,查詢表數據
(3)在客戶端A(此時未提交A的事務)上查詢數據,id=4298的stock并沒有變成800-50=750,還是步驟1中的stock=800,體現了可重復讀的含義~
(4)客戶端A提交事務,再次查詢到的數據才是客戶端B更新后的stock
(5)如果在步驟4停止,不提交A的事務,此時在客戶端A執行?update order_info set stock=stock-50 where id=4298會發現
stock變成的了700而不是750,也就是說客戶端A在update時用到了客戶端B更新的結果,這是由于:可重復讀這種隔離級別在select操作時候會使用快照版本,update、insert、delete時會使用當前實時版本以避免數據不一致性問題(下面是update的情況,delete和insert留給大家自己測試)
(6)接著測試一下可重復讀隔離級別的幻讀問題,客戶端A開啟新事務進行更新操作并查詢表數據
(7)新開客戶端B進行插入操作并提交事務
(8)客戶端A再次進行查詢操作,沒有查到客戶端B新插入的三星蓋樂世S9記錄,沒有出現幻讀的現象
(四)串行化
(1)設置當前事務隔離級別為"串行化",客戶端A開啟一個事務,然后查詢表初始數據
(2)客戶端B設置串行化隔離級別,開啟事務并查詢、更新數據,發現可以查詢但無法更新,因為客戶端A的查詢事務導致鎖表
串行化隔離級別的并發量極低,但是能較好的避免臟讀、幻讀問題.
4、spring的4種事務特性、5種隔離級別、7種事務傳播行為
?
?
?
總結
以上是生活随笔為你收集整理的记录一次线上mysql事务隔离级别引发的思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决Linux下vi或vim操作Foun
- 下一篇: 【Django】数据库主从配置