從零開始實現資料庫系統(3)——並發控制
我們希望多個事務儘可能的並發執行,來提高效率。但是並發執行的事務之間相互影響會導致資料庫狀態不一致。
1.鎖
一個很自然的方式是給事務要訪問的數據加鎖。鎖表示當前事務對此數據元素的獨佔權。在事務操作資料庫元素前都必須獲取該元素上的鎖。
讀寫鎖
有些事務可能只是想讀而不是修改某數據元素,我們有辦法讓這種情況更高效。讀寫鎖也叫共享鎖/排他鎖。讀和讀兼容,讀和寫互斥,寫和寫互斥。
我們在實現讀寫鎖時有一個當前讀事務的計數,當讀計數為0時才能申請到寫鎖。
兩階段鎖
有一種叫兩階段鎖的方法能夠保證事務是可串列化的,即:每個事務中,所有加鎖操作必須在解鎖操作之前。
死鎖
死鎖是指多個事務競爭資源出現的阻塞現象,一般是持有A資源申請B資源與持有B資源申請A資源相互等待。
避免死鎖方法:1是預防死鎖發生,2是檢測死鎖和恢復。比較簡單粗暴的方法是設定一個事務超時時間,超時以後回滾事務。
2.樂觀鎖
普通的鎖是一種悲觀鎖,它們假定只要不加鎖就會出錯。而樂觀鎖假定不會出現衝突,當檢測到衝突時回滾。
資料庫記錄讀取或修改數據元素的時間戳或者版本號。在修改時驗證數據在此期間是否被修改過。如果出現不一致,則重啟或者取消當前事務。
如果大多數事務是只讀的或者極少並發修改同一元素,則樂觀鎖更好。在高衝突時,悲觀鎖性能更好。
3 MVCC
除了通過延遲和終止事務來避免衝突以外,我們還可以通過對競爭對象進行拷貝多份來避免衝突。
多版本並發控制(MVCC)是在修改數據時,總是保持舊的版本不變而產生一個新版本的數據。讀操作在多個數據元素版本中找到一個合適的版本進行讀取。這樣讀和寫不再衝突,當然寫寫還是衝突的。
MVCC一般要和悲觀鎖或樂觀鎖結合使用。
事務隔離級別
有時候不能完全按照可串列化的要求來執行事務,在有些應用中可以做適當的妥協來提高性能。從需求的角度講,SQL定義了四種事務的隔離級別。
1. Read Uncommitted(讀取未提交內容)
可以讀到其他事務未提交的內容,可能在讀取後其他事務又撤銷回滾了。
2. Read Committed(讀取提交內容)
一個事務只能讀取到已提交事務的修改內容。當在事務執行期間另一個事務會產生提交,導致兩次讀取同一數據的內容不一樣。
3. Repeatable Read(可重讀)
事務並發執行期間,多次讀取同一數據元素相同。但是會讀到其他事務新增的數據。
4. Serializable(可串列化)
和每個事務順序執行的效果相同。
上面三種解決並發問題方法的不同組合和實現細節對應不同的隔離級別。
推薦閱讀:
※Mysql資料庫主從心得整理
※深入淺出hbase和bigtable
※Mysql優化
※劉寅:TiDB 工具鏈和生態
※資料庫面試題(開發者必看)
TAG:資料庫 |