一 概述程序員
在數據庫方面,對於非DBA的程序員來講,事務與鎖是一大難點,針對該難點,本篇文章試圖採用圖文的方式來與你們一塊兒探討。數據庫
「淺談SQL Server 事務與鎖」這個專題共分兩篇,上篇主講事務及事務一致性問題,並簡略的說起一下鎖的種類和鎖的控制級別。架構
下篇主講SQL Server中的鎖機制,鎖控制級別和死鎖的若干問題。併發
二 事務學習
1 何爲事務spa
預覽衆多書籍,對於事務的定義,不一樣文獻不一樣做者對其雖有細微差異卻大體統一,咱們將其抽象歸納爲:3d
事務:指封裝且執行單個或多個操做的單個工做單元,在SqlServer中,其定義表現爲顯示定義和隱式定義兩種方式。
基於如上的定義,咱們能夠將事務解剖拆分爲以下幾個點:版本控制
(1)事務是單個工做單元,這必定義,才使事務具備ACID屬性日誌
(2)事務是封裝操做的,如封裝基本的CRUD操做code
1 --事務 2 Begin Tran 3 SELECT * FROM UserInfo 4 INSERT INTO UserInfo VALUES('Alan_beijing',35) 5 UPDATE UserInfo SET Age=31 WHERE UserName='Alan_beijing' 6 DELETE UserInfo WHERE UserName='Alan_beijing' 7 Commit Tran
(3)事務在封裝操做時,能夠封裝單個操做,也能夠封裝多個操做(封裝多個操做時,應注意與批處理的區別)
(4)在SqlServer中,事務的定義分爲顯示定義和隱式定義兩種方式
顯示定義:以Begin Tran做爲開始,其中提交事務爲Commit Tran,回滾事務爲RollBack Tran,如咱們在一個事務中插入兩條操做語句
1 --顯示定義事務 2 Begin Tran 3 INSERT INTO UserInfo VALUES('Alan_shanghai',30) 4 INSERT INTO UserInfo VALUES('Alan_beijing',35) 5 Commit Tran
隱式定義:若是不顯示定義事務,SQL Server 默認把每一個語句看成一個事務來處理(執行完每一個語句以後就自動提交事務)
2 事務的ACID屬性
事務做爲單個工做單元,該定義使其具備ACID屬性,ACID屬性指原子性(Atomicity)、一致性(Consisitency)、隔離性(Isolation)和持久性(Durability)。
(1)原子性(Atomicity)
原子性指事務必須是原子工做單元,即對於事務的封裝操做,要麼所有執行,要麼全都不執行。以下狀況均會致使事務的撤銷或回滾。。。
a.事務提交以前,系統發生故障或從新啓動,SQL Server將會撤銷在事務中進行的全部操做;
b.事務處理中遇到錯誤,SQL Server一般會自動回滾事務,但也有少數例外;
c.一些不太嚴重的錯誤不會引起事務的自動回滾,如主鍵衝突,鎖超時等;
d.可使用錯誤處理代碼來捕獲一些錯誤,並採起相應的操做,如把錯誤記錄在日誌中,再回滾事務等;
(2)一致性(Consisitency)
一致性主要指數據一致性,即主要對象是數據。從宏觀上來講,指某一段時間區間,數據要保持一致性狀態,從微觀上來講,某個時間點數據要保持一致性狀態,咱們舉個例子,
倘若有兩個事務A和B對同一張表進行操做,A向表中寫數據,B向數據表中讀取數據,能夠猜想,B讀取的數據大體有三種粗粒度可能:
第一種可能:A還沒向數據表中寫入數據的狀態;
第二種可能:A已向數據表中寫入部分數據,但還未寫完的狀態;
第三種可能:A已向數據表中寫完數據;
如此,形成了事務的不一致性。
關於事務一致性,可能會發生 丟失更新,髒讀,不可重複讀和幻讀等問題,下文會詳細論述這些事務一致性問題。
(3)隔離性(Isolation)
隔離性指當兩個及其以上事務對同一邊界資源進行操做時,要控制好每一個事務的邊界,控制好數據訪問機制,確保事務只能訪問處於指望的一致性級別下的數據。
在SQL Server中,通常採用鎖機制來控制,下文中,咱們會詳細論述。
(4)持久性(Durability)
咱們對數據表進行操做時,通常會按照前後順序執行以下兩步:
第一步:將對數據表操做寫入到磁盤上數據庫的事務日誌中(持久還到磁盤事務日誌中);
第二步:完成第一步後,再將對數據表操做寫入到磁盤上數據庫的數據分區中(持久化到磁盤上數據庫分區中);
關於如上兩步,咱們來想一想可能發生的問題:
問題1:完成如上第一步以前,系統發生故障(如系統異常,系統重啓),數據庫引擎會怎麼作?
因爲未完成第一步,提交指令還未記錄到磁盤的事務日誌中,此時事務並未持久化,系統發生故障後,SQL Server
會檢查每一個數據庫的事務日誌,進行恢復處理(恢復處理通常分爲重作階段和撤銷階段),此時的恢復處理爲重作階段,即提交指令還未記錄到磁盤的事務日誌中,
數據庫引擎會撤銷這些事務所作的全部修改,這個過程也成爲回滾。
問題2:完成如上第一步但還未完成第二步,系統發生故障(如系統異常,系統重啓),數據庫引擎會怎麼作?
完成第一步後,提交指令已記錄到磁盤的事務日誌中,不管數據操做是否被寫入到磁盤的數據分區,此時事務已持久化,系統發生故障後,SQL Server
會檢查每一個數據庫的事務日誌,進行恢復處理(恢復處理通常分爲重作階段和撤銷階段),此時的恢復處理爲重作階段,即因爲數據修改尚未運用到數據分區的事務,
數據庫引擎會重作這些事務所作的全部修改,這個過程也成爲前滾。
三 事務的隔離級別和隔離級別產生的一致性問題
1 未提交讀(READ UNCOMMITTED)
未提交讀(READ UNCOMMITTED)指讀取未提交的數據,此時產生的數據不一致性,咱們稱爲數據髒讀。
1.1 未提交讀爲何會產生數據髒讀
未提交讀是最低級的隔離級別,在這個隔離級別運行的事務,讀操做是不須要請求共享鎖的,若是讀操做不須要共享鎖,就不會產生與持有排它鎖的事務操做發生衝突,
那麼也就是說,在這個事務隔離級別,讀操做能夠與寫操做同時進行,互不排斥,讀操做能夠讀取寫操做未提交的修改,從而形成數據的不一致性,這種狀況,咱們稱
數據髒讀。
1.2 圖解數據髒讀
1.3 SQL演示數據髒讀
2 已提交讀(READ COMMITTED)
已提交讀(READ COMMITTED)指只能讀取已提交事務的數據,是防止數據髒讀的最低隔離級別,也是SQL Server默認的隔離級別,它要求讀操做必須得到共享鎖後
才能進行操做,防止讀取未提交的修改,雖然已提交讀能防止產生數據髒讀,但卻不可避免不可重複讀數據一致性問題。
2.1 爲何已提交讀可以防止數據髒讀
已提交讀只容許讀取事務已提交的數據,它要求讀操做必須得到共享鎖才能盡心操做,而讀操做的共享鎖與寫操做的排他鎖是互斥的,二者互斥會發生衝突,因此讀操做
在讀取數據時,必須等待寫操做完成後,才能獲取共享鎖,而後才能讀取數據,此時讀取的數據是已經提交結束的數據,所以就防止了數據髒讀的問題。
2.2 SQL演示已提交讀
2.3 爲何已提交讀會產生不可重複讀問題
咱們知道,雖然已提交讀能得到共享鎖,然而,讀操做一完成,就會當即釋放資源上的共享鎖(該操做不會在事務持續期間一致保留共享鎖),如此就會產生一個問題,
即在一個事務處理內部對相同數據資源讀操做之間,沒有共享鎖會鎖定該資源,致使其餘事務能夠在兩個讀操做之間更改數據資源,讀操做於是可能每次獲得不一樣的
取值,這種現象稱爲數據的不可重複讀。
2.4 圖解不可重複讀
3 可重複讀(REPEATABLE READ)
爲了防止不可重複讀現象,SQL Sever中採用隔離級別升級的方式,即將已提交讀升級爲可重複讀。在可重複讀隔離級別下,事務中的讀操做不只能得到共享鎖,
並且得到的共享鎖一直保持到事務完成爲止, 在該事務完成以前,其餘事務不可能得到排他鎖來修改這一數據,如此,便實現了可重複讀,防止了不可重複讀造
成的數據不一致性。可重複讀不只能解決不可重複讀數據不一致性問題,還能解決丟失更新問題。然而,可重複讀也存在問題,那就是死鎖和幻讀等問題。
3.1 SQL演示可重複讀
3.2 何爲丟失更新?
在比可重複讀低的隔離級別中,兩個事務在讀取數據以後就再也不持有該資源的任何鎖,此時,兩個事務都能更新這個值,
從而發生最後事務更新的值覆蓋前面事務更新的值,從而形成數據的丟失,這稱爲丟失更新。
3.3 圖解丟失更新
4 可序列化(SERIALIZABLE)
4.1 何爲幻讀?
咱們知道,在可重複讀隔離級別下,讀事務持有的共享鎖一直保持到該事務完成爲止,可是事務只鎖定查詢第一次運行時找到的那些數據資源(如,行),
而不會鎖定查詢結果範圍之外的其餘行(其實,控制事務時,有數據庫架構級別,表,頁和行等)。所以,在同一事務中進行第二次讀取以前,若其餘事
務插入新行,而且新行能知足讀操做的查詢過濾條件,那麼這些新行也會出如今第二次讀操做返回的結果中,這些新行稱爲幻影子,也叫作幻讀。
4.2 圖解幻讀
4.3 如何解決幻讀?
SQL SERVER中,更高級別的可序列化(SERIALIZABLE)可以解決該問題。
4.4 何爲可序列化(SERIALIZABLE)?
大多數時候,可序列化(SERIALIZABLE)隔離級別的處理方式和可重複都得處理方式是相似的,只不過,可序列化(SERIALIZABLE)隔離級別
增長了一個新的內容——邏輯上,這個隔離級別會讓讀操做鎖定知足查詢搜索條件的鍵的整範圍,這就意味着讀操做不只鎖定了知足查詢搜索
條件的現有的那些行,還鎖定了將來可能知足查詢搜索條件的行。
5 SNAPSHOT
略。
四 事務的隔離級別總結
下表總結了每種隔離級別與邏輯一致性問題,檢測衝突和行版本控制之間關係
五 鎖定
1 兩種併發控制模型
關於併發控制模型,主要有兩種,即悲觀控制模型和樂觀控制模型。
(1)悲觀控制模型: 該模型假設老是存在多個事務對同一資源操做(讀/寫),即假定衝突老是會發生。在SQL Server中,採用事務
隔離級別來控制(也可叫作採用鎖來控制)。通常在事務發生衝突前進行控制,也叫事前控制;
(2)樂觀控制模型:該模型與悲觀控制模型是對立的,即該模型老是假設系統中並不存在或較少存在多個事務對同一資源操做(讀/寫)
,即假定衝突是不會發生的或不多發生的。在SQL Server中,採用行版本控制來處理。通常在事務發生衝突後進行控制,也叫過後
控制;
2 何爲鎖定及鎖定的種類
2.1 何爲鎖定
鎖定,指在併發操做時,確保數據的一致性所採用的一種手段。在SQL Server中,採用鎖機制與事務隔離級別來控制數據的一致性,
2.2 鎖定的種類
經常使用的四大類鎖包括:共享鎖,意向鎖,更新鎖和排他鎖。
(1)共享鎖:在SQL SERVER中,當事務要讀取數據時,須要獲取共享鎖。
(2)意向鎖:在SQL SERVER中,準確來講,意向鎖並非一種獨立的鎖,其主要做用在於獲取鎖的控制粒度(如,頁,表,行等)。
(3)更新鎖:在SQL SERVER中,準確來講,更新鎖並非一種獨立的鎖,而是由共享鎖和排它鎖組成的混合鎖,其隔離級別高於共享鎖,
低於排他鎖,更新鎖可以預防鎖升級而產生的死鎖。
(4)排它鎖:在SQL SERVER中,當事務要寫數據、更細數據和刪除數據時,須要獲取排他鎖。
3 鎖的控制粒度
在SQL SERVER中,鎖能夠控制表,頁和行等資源。
六 參考文獻
【01】Microsoft SqlServer 2008技術內幕:T-SQL 語言基礎
【02】Microsoft SqlServer 2008技術內幕:T-SQL 查詢
七 服務區
有喜歡的朋友,能夠看一下,不喜歡的的朋友,勿噴,謝謝!!
八 版權區