背景:數據庫系統容許多用戶操做,因此同一時間處理的事務可能多大上百個,所以必需要引入併發控制來保證數據的可靠性。數據庫
在併發環境下,事務的隔離性很難保證,所以會出現不少併發一致性問題。併發
丟失修改指一個事務的更新操做被另一個事務的更新操做替換。通常在現實生活中常會遇到,例如:T1 和 T2 兩個事務都對一個數據進行修改,T1 先修改並提交生效,T2 隨後修改,T2 的修改覆蓋了 T1 的修改。3d
讀髒數據指在不一樣的事務下,當前事務能夠讀到另外事務未提交的數據。例如:T1 修改一個數據但未提交,T2 隨後讀取這個數據。若是 T1 撤銷了此次修改,那麼 T2 讀取的數據是髒數據。對象
不可重複讀指在一個事務內屢次讀取同一數據集合。在這一事務還未結束前,另外一事務也訪問了該同一數據集合並作了修改,因爲第二個事務的修改,第一次事務的兩次讀取的數據可能不一致。例如:T2 讀取一個數據,T1 對該數據作了修改。若是 T2 再次讀取這個數據,此時讀取的結果和第一次讀取的結果不一樣。blog
幻讀本質上也屬於不可重複讀的狀況,T1 讀取某個範圍的數據,T2 在這個範圍內插入新的數據,T1 再次讀取這個範圍的數據,此時讀取的結果和和第一次讀取的結果不一樣。繼承
產生併發不一致性問題的主要緣由是破壞了事務的隔離性,解決方法是經過併發控制來保證隔離性。併發控制能夠經過封鎖來實現,可是封鎖操做須要用戶本身控制,至關複雜。數據庫管理系統提供了事務的隔離級別,讓用戶以一種更輕鬆的方式處理併發一致性問題。圖片
數據庫一致性(Database Consistency)是指事務執行的結果必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。保證數據庫一致性是指當事務完成時,必須使全部數據都具備一致的狀態。在關係型數據庫中,全部的規則必須應用到事務的修改上,以便維護全部數據的完整性。事務
有如下兩個規定:資源
鎖的兼容關係以下:io
使用意向鎖(Intention Locks)能夠更容易地支持多粒度封鎖。
在存在行級鎖和表級鎖的狀況下,事務 T 想要對錶 A 加 X 鎖,就須要先檢測是否有其它事務對錶 A 或者表 A 中的任意一行加了鎖,那麼就須要對錶 A 的每一行都檢測一次,這是很是耗時的。
若是要對一個數據對象加上IS鎖,那就表明準備向它的後裔節點加上S鎖,例如若是要對R1中某個元組加S鎖,則要首先對關係R1和數據庫加IS鎖 。
若是要對一個數據對象加IX鎖,就表明準備要對它的後裔節點加上X鎖。例如要對R1中某個元組加X鎖,則要首先對關係R1和數據庫加IX鎖。
SIX鎖爲S鎖加上一個IX鎖,也就是想要讀整個表,並向對其中的一些數據進行修改,這個鎖稍強於除X互斥鎖之外的其餘鎖。
意向鎖在原來的 X/S 鎖之上引入了 IX/IS,IX/IS 都是表鎖,用來表示一個事務想要在表中的某個數據行上加 X 鎖或 S 鎖。有如下兩個規定:
經過引入意向鎖,事務 T 想要對錶 A 加 X 鎖,只須要先檢測是否有其它事務對錶 A 加了 X/IX/S/IS 鎖,若是加了就表示有其它事務正在使用這個表或者表中某一行的鎖,所以事務 T 加 X 鎖失敗。
各類鎖的兼容關係以下:
解釋以下:
事務 T 要修改數據 A 時必須加 X 鎖,直到 T 結束才釋放鎖。
能夠解決丟失修改問題,由於不能同時有兩個事務對同一個數據進行修改,那麼事務的修改就不會被覆蓋。
在一級的基礎上,要求讀取數據 A 時必須加 S 鎖,讀取完立刻釋放 S 鎖。
能夠解決讀髒數據問題,由於若是一個事務在對數據 A 進行修改,根據 1 級封鎖協議,會加 X 鎖,那麼就不能再加 S 鎖了,也就是不會讀入數據。
在二級的基礎上,要求讀取數據 A 時必須加 S 鎖,直到事務結束了才能釋放 S 鎖。
能夠解決不可重複讀的問題,由於讀 A 時,其它事務不能對 A 加 X 鎖,從而避免了在讀的期間數據發生改變。
加鎖和解鎖分爲兩個階段進行。
使用兩段封鎖協議的緣由:若是不使用封鎖,或者光對併發執行的事務加鎖,對鎖的申請和釋放時間卻不加控制,就不能保證事務執行的可串行性,數據庫的一致狀態仍有可能被破壞。
擴展階段就是加鎖的過程,收縮階段就是釋放鎖的過程。
是指經過併發控制,使得併發執行的事務結果與某個串行執行的事務結果相同。串行執行的事務互不干擾,不會出現併發一致性問題。
是併發事務正確調度的準則, 一個給定的併發調度,當且僅當它是可串行化的,才能被認定爲是正確調度。
事務遵循兩段鎖協議是保證可串行化調度的充分條件。例如如下操做知足兩段鎖協議,它是可串行化調度。
lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
但不是必要條件,例如如下操做不知足兩段鎖協議,但它仍是可串行化調度。
lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)
若併發的事務都遵照2PL, 則這些事務的任何併發調度都是可串行化的。
一次封鎖協議能夠避免死鎖的發生,可是遵循兩端鎖協議有可能發生死鎖,由於上鎖並非一塊兒完成的,在未上鎖的時候,其中一個須要的數據被其餘的事務拿到了鎖,致使本來的事務沒辦法拿到鎖,致使死鎖的發生。
指的是不一樣的事務對同一個數據的讀寫操做和寫寫操做。
一個讀一個寫,那麼狀態就不一致了,兩個寫操做也會致使數據庫狀態丟失、不一致
可串行化操做的充分條件:
除了要求知足兩段鎖協議規定以外,還要求事務的排他鎖必需要在事務提交以後釋放。
能夠解決髒數據的讀取問題。
要求在知足兩段鎖協議以外,全部的鎖都要在事務提交以後釋放。
事務能夠按照其提交的順序完成串行化。
MySQL 中提供了兩種封鎖粒度:行級鎖以及表級鎖。
應該儘可能只鎖定須要修改的那部分數據,而不是全部的資源。鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。
可是加鎖須要消耗資源,鎖的各類操做(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增長系統開銷。所以封鎖粒度越小,系統開銷就越大。
在選擇封鎖粒度時,須要在鎖開銷和併發程度之間作一個權衡。
因此係統在檢查一個數據對象是否有鎖的時候不只要檢查有沒有顯示的加上鎖,還要檢查其上級節點有沒有被加上鎖。同時也不能忘了檢查其子節點有沒有鎖與即將要加上的鎖衝突,若是出現衝突也不能上鎖。
部分圖片與文字資料來自CS-Note