事務是什么
在SQL Server中事務是構成一個工作邏輯單元的一系列任務,也就說多個任務放在一起執行,這些任務要么全部執行成功,要么全部執行失敗。
通過事務我們可以保證數據的完整性,例如:用戶A給用戶B轉1000塊錢,如果從用戶A的賬號中扣了1000塊,但是在向用戶B賬號添加1000塊的時候執行失敗,這個時候用戶A說自己轉了,用戶B卻有沒收到,兩個還不得打起來。所以針對於這種情況,需要使用事務,其中從用戶A賬號扣除1000塊錢是一個任務,向用戶B賬號添加1000塊是另一個任務,這兩個任務如果都執行成功說明轉賬成功,如果都執行失敗,這1000塊還在用戶A賬上。
ACID屬性
在了解事務之前,我們還是要先了解一些基本概念。
事務必須滿足一組需求,稱之為ACID屬性,分別指的是:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。
原子性
根據我們學過的化學知識,分子是原子組成,而原子是不可再分的,正如開篇對事務的定義,事務里面的任務只能全部執行成功或全部不執行這兩種結果,如果只有部分任務執行成功,就違反了原子屬性。
一致性
事務必須保證數據的一致性,雖然在事務處理期間內允許數據庫處於不一致的狀態下,但是在事務完成時必須是一致的。
例如,假設Orders表和OrderDetails表之間存在一個基於OrderID字段的外鍵,這個約束確保OrderDetails表中存在OrderID之前,該OrderID必須先存在於Orders表中。如果一個事務如果沒有Orders表寫入記錄,但給OrderDetails表寫入了記錄,數據庫就處於不一致的狀態。
隔離性
每個事務都是隔離的,隔離有不同的隔離級別,后面會詳細講解。
持久性
事務的持久性是指事務提交之后,就保持這個狀態,即如果事務修改了某行數據,這個事務提交之后,這個事務就不會再改變該行數據,除非再次執行事務。
如果使用事務
在SQL Server主要使用下面三個命令實現事務的編程:
Begin Transaction:開始事務
Commit Transaction:提交事務
Rollback Transaction:回滾事務
一旦開始事務,要么提交,要么回滾,否則已開始的事務在事務處理期間會一直保持鎖定,可能阻塞其他事務的執行。簡單示例如下:
Begin Try Begin Transaction select departmentId as DeptId,Name from HumanResources.Department where name between 'A' And 'G' Commit transaction End Try Begin Catch; Rollback Transaction Return; End Catch;
理解SQL Server鎖定
SQL Server使用鎖實現ACID隔離屬性,鎖確保一個事務的修改不受另一個事務修改事務的影響,鎖定數據也存在不同的級別。
按粒度划分
行鎖:鎖定單行,這是最小的鎖
頁面鎖:鎖定一頁或8KB,一個頁存在一行或多行
區鎖:鎖定8個頁面或64KB
表鎖:鎖定整個表
數據庫鎖:鎖整個數據庫,這個鎖主要用於架構更改時
鍵鎖:鎖索引上的節點
SQL Server會自動管理鎖的大小,盡可能使用較小的鎖,因為較小的鎖允許更多的事務訪問數據,另外,每個鎖都需要在內存中保存鎖的信息,所以鎖越少越好。SQL Sever在檢測到內存壓力時,會提升鎖的級別。
按模式划分
共享鎖:
數據庫默認的隔離級別使用的就是共享鎖,即多個進程同時擁有,因為是大家的,所以只能看不能改,而且共享鎖不能用於當前正在修改的行/頁面/表上。
排他鎖:
顧名思義,就是我的東西,不允許別人看,更不允許修改,通常在事務對數據執行寫入時使用排它鎖。
更新鎖:
更新鎖意味着,事務准備執行排他鎖,當前正在掃描數據,以確定它希望鎖定的行。可以簡單看成,打算轉變為排它鎖的共享鎖。
按模式划分,還有其他類型,例如:意向共享鎖、意向排他共享鎖、意向排他鎖。
事務隔離級別
在了解事務的隔離級別之前,必須先明白三個概念:臟讀取、不能重復的讀取和幻影行。
臟數據
所謂的臟數據,其實值得就是還沒有其他的數據,即沒有正真寫入到數據庫的數據。那么這樣的數據是怎么來的呢?
通常,臟數據是由其他事務產生,但是在該事務並未提交,而這數據已經被其他事務獲取使用,顯然這樣的數據是有問題的。
不能重復的讀取
簡單的理解,就是第一次執行事務(但未提交)和第二次執行該事務獲取到的數據不一樣,即第二次事務開始之前,數據被修改了,當然在一般情況下這樣的數據沒問題,但是對於一些隔離級別要求很高,就要求兩次執行相同的事務獲取的結果必須一樣,即重復的。
幻影行
重復的讀取,指定是選中的行,這個行是確定的,但是有時事務獲取的是一個行范圍,在第一次執行事務(但未提交)和第二次執行該事務獲取的行范圍就可能存在不同,為啥呢?因為別的事務可能會去新增或刪除行,而這些行我們叫做幻影行。
了解這些基本概念之后,我們看看具體事務的隔離級別。
級別1——Read Uncommitted
這是最低級別的隔離,允許讀取沒有提交的事務修改的數據,即上面說的臟數據。這個級別在讀取數據的時候不設置共享鎖。
示例如下:
set Transaction Isolation level Read Uncommitted Begin Transaction update HumanResources.Department set Name='ABC ddd' Where DepartmentID=1 Commit transaction
級別2——Read Committed
SQL Server中默認的事務隔離級別就是Read Committed,確保一個事務不能讀取另外一個事務已修改但未提交的數據。
級別3——Repeatable Read
在Repeatable Read中,任何在事務處理過程中獲得的共享鎖都會保持下去,直到事務提交為止。這不同於Read Committed隔離級別,Read Committed只在正在讀取的數據上擁有共享鎖。Repeatable Read級別能夠保證讀取到重復的數據。
級別4——Serializable
這個最嚴格的隔離級別禁止出現所有的事務錯誤:臟數據、不可重復的讀取和幻影行。
這個隔離級別可用於絕對事務完整性比性能更重要的數據庫。銀行、會計和競爭激烈的銷售數據庫(如股票市場)。