資料庫事務併發產生的問題以及事務的隔離級別

王若伊_恩賜解脫發表於2021-01-04

之前我們談到過,資料庫通過調整事務之間的隔離級別來提高事務的效能。
那麼接下來,我們來首先說說事務之間可能互相遇到的問題。

大家都知道事務只有提交後,才會真正的持久化到硬碟,倘若出現出現了回滾的操作,則事務所有操作的影響都會被回退掉。那麼假若事務在執行過程中,其他事務讀取到了當前的操作結果,但是當前事務後邊回滾了,那麼其他事務相當於讀取到了錯誤的資料。
舉個例子
老闆告訴HR,技術員工從下個月開始漲工資。技術小A從小道訊息得知後,非常開心,準備把自己的單車換成摩托。後邊老闆發現公司的債務堆積嚴重,告知HR取消該加薪計劃。得知真相的小A眼淚流下淚,只能含著淚去找摩托店老闆退貨。
流程如下圖:

理論上小A等員工不應該從側面提前獲知公司的加薪計劃,而應該在公司正式發文後(事務提交後)才可獲知。這個問題就是我們常說的髒讀。此時的隔離級別我們稱之為讀未提交,也就是說還沒有正式公佈的資料,可以被提前獲知到。(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )
如何解決這個問題呢?
公司特別進行了申明,任何未經公司正式發文的訊息,全部為不實訊息,大家不可以信賴,出現任何問題後果自負,大家只能相信眼見為實的那些訊息。這種隔離級別我們稱之為讀已提交,也就是隻能讀到公司正式發文的資訊,對於那些未通過正式發文的訊息,直接無視掉。
問題好像已經解決了。
年會前公司正式發文,由於今年業績成長明顯,經討論, 全員加薪。
小A看了看自己騎了兩年的單車,決定換一輛摩托。正所謂搏一搏單車變摩托。
於是小A興沖沖的跑到摩托車行,預定了自己中意已久的摩托。
然而接下來小A在參加年會的過程中,老總在會議上特別宣佈,由於上一年公司業績的特別突出,經過公司董事會的宣佈,包括小A在內的所有員工,特別增發配股。
小A看了看微信已經給摩托車老闆轉發的定金,又看了看最新的路虎,陷入的沉思。正所謂賭一賭摩托變路虎,年會結束後,小A火速聯絡摩托車老闆,一哭二鬧的總算把押金退了,去隔壁的4S店下單了路虎。
流程如下圖:

對於這種每次讀取到待遇都不一樣,導致處理過程中出現了錯誤的處理的場景,我們稱之為不可重複讀。啥意思呢?也就是說即使公司正式發文後(提交後),也可能存在不確定性,因為公司可能反覆提交資料,導致你拿到的資料仍然是髒資料,甚至你已經根據歷史資料進行了錯誤的處理。此時的隔離級別我們稱之為讀已提交。
那麼怎麼解決這個不可重複讀的問題呢?
也就是你操作期間,其他人不能改資料。很簡單,你用什麼資料鎖住什麼資料就好了,如果你需要根據薪酬要做出消費的判斷,那麼只要鎖住薪酬就好了。

這樣好像問題已經解決了,但是通過一系列操作預訂完路虎的你,回家發現,當初私房錢買的比特幣,現在已經漲到3萬美金了,摺合下來資產都過億了。(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )望著一串你的小屏手機都快顯示不下的數字,你再次陷入沉思。從沉思緩過來後,你撥通了路虎店的電話,又是一頓一哭二鬧三上吊,你去了旁邊的瑪莎拉蒂店下了訂單。
整體的流程如下:


為啥明明已經鎖定了薪酬,可是收入卻仍然無情的增長。
原因很簡單,你只鎖定住了既有的資料,來自單位的薪酬,沒有鎖住外界新增的資料,導致讀到的資料仍然不夠準確,無法做出正確的處理。這種異常場景我們稱之為幻讀,也就是因為新增資料導致的讀不一致性。而當前的這種隔離級別稱之為可重複讀。也就是我們可以反覆的讀取之前已經讀取到的資料,但是新增的資料,我們仍然可能會讀取到,讀不一致性仍然存在
如何解決幻讀的問題呢?
答案很簡單,還是加鎖,之前加鎖是對某些已經存在的資料加鎖,現在加鎖,是對全域性加鎖,誰要操作,誰獲取到全域性的鎖。(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )至此也就不存在併發場景了,也就更不存在併發問題了。這種隔離級別我們稱之為序列化。
至於這幾種隔離級別在innodb中是如何實現的,確實是比較複雜,一兩句話難以說清,我會在後文中專門講解
下邊我們總結一下前文所提到的概念:
1、 髒讀
讀到了其他事務未提交的資料。(也就是髒頁中的資料,這個後文中我會專門講解)
2、 不可重複讀
在事務中每次讀取到的資料是別人已經提交的資料,但是由於存在併發修改(update delele),每次讀取到的資料不一致
3、 幻讀
對於新插入的資料造成的讀不一致性,我們稱之為幻讀
這三個問題都屬於存在併發事務時,資料的前後讀不一致的問題。解決辦法就是通過資料庫的不同隔離機制,(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )來規避掉這些問題。
1、 讀未提交 Read Uncommitted
事務未提交的資料修改,對其他事務也是可見的
未解決髒讀,不可重複讀,幻讀
2、 讀已提交 Read Committed
一個事務開始後,只能看到已經提交的事務做出的修改
解決髒讀,未解決不可重複讀,幻讀
3、 可重複讀 Repeatable Read
一個事務開始後,對於已經查詢出的資料,再次反覆查詢獲取到的資料是一樣的
解決了髒讀,不可重複讀,未解決幻讀
這裡要特別注意下,可重複讀級別儘管不要求解決幻讀問題,但是innodb儲存引擎卻不存在該問題,這個我會再接下來的部落格中專門解釋該問題
4、 序列化  Serializable
最高階別,強制事務進行序列操作
解決了所有資料庫併發問題

相關文章