共享鎖和排它鎖(Shared and Exclusive Locks)
并發(fā)控制
提到共享鎖和排它鎖就不得不提并發(fā)控制(Concurrency Control),并發(fā)控制可以解決臨界資源操作時不一致的情況產(chǎn)生,保證數(shù)據(jù)一致性常見的手段就是鎖和數(shù)據(jù)多版本(Multi Version)
直接加鎖
這種方式會導(dǎo)致被加鎖的資源都被鎖住,讀取任務(wù)也無法執(zhí)行直到鎖釋放,所有執(zhí)行的任務(wù)相當(dāng)于串行化方式,簡單粗暴,不能并發(fā)
共享鎖(Shared Locks)簡稱為 S 鎖
讀取數(shù)據(jù)時候可以加 S 鎖
共享 (S) 鎖允許并發(fā)事務(wù)讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務(wù)都不能修改數(shù)據(jù)。一旦已經(jīng)讀取數(shù)據(jù),便立即釋放資源上的共享 (S) 鎖,除非將事務(wù)隔離級別設(shè)置為可重復(fù)讀或更高級別,或者在事務(wù)生存周期內(nèi)用鎖定提示保留共享 (S) 鎖
排它鎖 (Exclusive Locks)簡稱為 X 鎖
修改數(shù)據(jù)時候加 X 鎖
排它 (X) 鎖可以防止并發(fā)事務(wù)對資源進(jìn)行訪問。其它事務(wù)不能讀取或修改排它 (X) 鎖鎖定的數(shù)據(jù)
共享鎖之間可以并行,排它鎖和共享鎖之間互斥,也就是說只要共享鎖開啟沒有釋放掉的時候,更新鎖是不能搶占的,此時其他讀取同資源的操作可以進(jìn)行讀取不受限制;同理排它鎖開啟時候只要沒有釋放其他不管是排它鎖還是共享鎖都不可以搶占資源直到鎖釋放
死鎖
死鎖是指兩個或兩個以上的進(jìn)程(線程)在運(yùn)行過程中因爭奪資源而造成的一種僵局(Deadly-Embrace) ) ,若無外力作用,這些進(jìn)程(線程)都將無法向前推進(jìn),列舉一些可能會造成死鎖的誘因
- 如上所述并發(fā)修改同一記錄
- 事務(wù)之間對資源訪問(表)順序的交替進(jìn)行,與第一條大同小異,上升到鎖表的級別
- 數(shù)據(jù)量龐大時候索引建立機(jī)制不行,經(jīng)常掃全表操作,也會造成資源阻塞死鎖
- 愿意在代碼里開大事務(wù)然后對數(shù)據(jù)庫一頓操作互相等待,容易引發(fā)死鎖,所以代碼里要節(jié)儉對事務(wù)的開銷,以及事務(wù)開銷時候盡可能有效合理利用資源
數(shù)據(jù)多版本
上面講到 X 鎖占領(lǐng)后其他 S 鎖沒法占用導(dǎo)致只要寫沒完成讀就不能進(jìn)行并發(fā)查詢,InnoDB 引入了數(shù)據(jù)多版本概念去解決這一問題
核心原理簡單講就是 clone 了一個版本數(shù)據(jù)進(jìn)行修改,比如原有的數(shù)據(jù)版本號是 Version0,這個時候進(jìn)行寫操作 clone 了一份版本號 V1,這個時候?qū)?V1 版本數(shù)據(jù)進(jìn)行修改寫入操作;與此同時其他查詢讀任務(wù)并發(fā)進(jìn)來一樣可以讀取 V0 版本數(shù)據(jù)不受任何影響,這樣就解決了在數(shù)據(jù)更新回寫之前不能讀取的問題,進(jìn)一步提高了數(shù)據(jù)庫引擎處理并發(fā)的能力
InnoDB 如何操作多版本控制
這個需要簡單講一下 redo,undo 和回滾段
- redo:事務(wù)提交后需要把數(shù)據(jù)刷盤,原有的機(jī)械磁盤情況下效率很低(固盤另說),隨機(jī)寫性能低,這樣就先放到 redo 日志中,定期把一批數(shù)據(jù)刷盤,巧妙的利用 redo 日志把隨機(jī)寫變成了順序?qū)?/li>
- undo:事務(wù)沒有提交之前可能會 rollback,undo 就是把就得數(shù)據(jù)鏡像放到 undo 日志里,回滾時恢復(fù)數(shù)據(jù)
- 存儲 undo 日志地方是回滾段,事務(wù)提交回滾段日志可以刪除,回滾時查找回滾段記錄復(fù)原,也可以理解為舊的數(shù)據(jù)存儲在回滾段中
InnoDB 本身就是 MVCC 多版本并發(fā)控制引擎,通過讀取舊版本數(shù)據(jù)來降低并發(fā)事務(wù)的鎖沖突,提高任務(wù)的并發(fā)度,與 MyISam 比不單單只是支持事務(wù)那么簡單