這幾天面試多次被問到了資料庫事務機制、隔離等級、樂觀鎖悲觀鎖類的問題,之前對這些只能說有所了解,有些概念還停留在記憶層面,沒有理解,所以回答的不好。後面翻書學習了下,理解了一些東西,在此做一個記錄。
什麼是事務?
事務我理解的是一個完整的業務行為,一個業務行為可能包含多個動作,這個完整的動作就構成一個事務。比較經典的例子是銀行轉賬,A帳戶轉到B帳戶,需要兩個動作:A帳戶減,B帳戶加,必須保證這兩個動作要么都做,要么都不做。
事務具有ACID特徵,具體包括:
● 原子性(atomicity):原子性是說事務的不可分割,要麼全成功,要麼全失敗,不可部分成功,部分失敗。半途失敗的情況下,需要打掃戰場,也就是資料回滾。
● 一致性(consistency):一致性是說交易的最後結果,要確保資料上沒有異常。一致性是強調結果,是建立在原子性上實現的,也就是說能保證原子性,那就會有一致性的結果。
● 隔離性(isolation):隔離性是說事務沒有提交前對其他事務是不可見的,事務間資料是隔離的(當然不同級別隔離程度不一樣)。
● 持久性(durability): 事務提交後會持久化,可以長久保存。
事務隔離等級
在了解事務的隔離等級之前,需要明白資料讀取的幾個概念:
# ● 髒讀:就是讀到了別人還沒提交的資料。
● 可重複讀:就是同一個事物內的兩次查詢,中間如果別人修改了查詢內的記錄且提交了,對第二次查詢是不可見的,不會出現同筆記錄兩次查詢不一致問題。
● 幻讀:就是一個事物內的兩次查詢,中間如果別人增加了記錄並且提交了,第二次查詢能查詢到的,會出現和第一次記錄不一致的現象。
交易的控制分很多個級別,級別的高低決定隔離的程度,MySQL中分四個級別:
● 讀未提交:這種級別是最低的,A事務的修改沒有提交對B事物是可見的,會出現資料的髒讀,一般情況下不會用到此種類型。
● 讀已提交:A事物的修改提交後才對B可見,這種情況會出現資料的幻讀的問題,兩次查詢的結果不一樣。
● 可重複讀:是MySQL預設的級別,這種級別事物內的兩次查詢,中間其他修改了某筆記錄,對其他事務是不可見的,保證了重複查的情況下同筆記錄的一致性,但是對於新增的情況其他事務是可見的,所以還是會出現新增幻讀的現象。
● 可串列化:交易之間是串列執行的,對查詢到的每筆記錄都加鎖,會出現阻塞的情況,並發情況下會造成嚴重的效能問題,所以一般也不會用到這種類型。
隔離等級一覽圖
#交易的隔離實作
交易當中的隔離是透過兩種方式控制:一種是鎖的方式,透過時間上的挫開達到隔離;另一種是版本控制的方式,記錄多個版本達到隔離。
1、鎖定
MySQL當中的鎖定分讀鎖定和寫鎖,讀鎖因為是讀取資料所以可以多個同時讀取同一份數據,具有共享性質;寫鎖涉及到資料的變動,所以和其他寫鎖和讀鎖是相衝突的,具有排他性質。
從鎖的粒度上分錶級鎖和行級鎖,表鎖一般發生在對錶結構的修改或對全表更新的時候,會阻塞所有對這張表的讀寫操作;行級鎖一般發生在指定記錄更新的時候,只會鎖定指定記錄。鎖的粒度越小並發度越高,能優先行級鎖盡量不要表鎖,和程式中鎖的粒度是一樣的原則。
2、多版本並發控制
MySQL為了效能考慮除了行級鎖定以外還是另外一種方式,多版本並發控制,這中控制是由存儲引擎實現。
書中說明了InnoDB一種簡單的實作方式,這種方式是採用一筆記錄多個版本的方式,每筆記錄上增加了兩個隱藏列,一個是建立版本號,一個是刪除版本號,每開啟一個事務都會分配一個事務版本號,事務版本號是遞增的,事務內操作都會根據這個版本號進行比較。具體如下:
● 查詢時:查詢目前事務之前存在的記錄和本事務建立的記錄,且沒有被刪除的,即:建立版本號 目前版本號)
● 插入時:記錄的建立版本號為目前事務版本號。
● 刪除時:更新記錄的刪除版本號碼為目前交易版本號。
● 更新時:插入一筆新記錄,建立版本號為目前交易版本號,同時將原記錄刪除版本號改為目前交易版本號,代表已經刪除。實際上這裡的更新相當於刪除再加一筆記錄。
3、樂觀鎖和悲觀鎖
鎖從使用的角度又分悲觀鎖和樂觀鎖,悲觀鎖是持有很悲觀的態度,認為我查到的資料都有可能被別人修改,所以查詢的時候就把這一批資料鎖起來,不讓別人操作;樂觀鎖是持有很樂觀的態度,認為我查到的資料基本上不可能被別人修改,所以查詢的時候不鎖住這批數據,修改提交的時候再確認有沒有被別人修改,有種亡羊補牢,為時不晚的意思。
樂觀鎖定與悲觀鎖定的實作:
● 悲觀鎖定可以在資料庫層級很簡單的解決,利用select ... for update,在查詢的時候就鎖定這部分數據。
● 樂觀鎖的實現較悲觀鎖複雜,可以在資料庫在一個版本號的列,更新的時候版本號都1,以此來確認我查出來的數據後面有沒有別人修改,已修改的不更新或程式拋一個異常。
使用樂觀鎖定還是悲觀鎖定:
從效能的角度考慮樂觀鎖定效能較好,在查詢到更新這段時間沒有鎖定操作,但是實現起來沒有悲觀鎖簡單,可能出錯。所以要考慮的因素是系統的並發高不高?出現衝突的機率有多大?並發高的情況下選用樂觀鎖更好,反之選用悲觀鎖這種簡單的方式更好。
推薦mysql影片教學,網址:https://www.php.cn/course/list/51.html
#以上是MySQL資料庫事務的機制【總結】的詳細內容。更多資訊請關注PHP中文網其他相關文章!