SQL2005中的事務與鎖定(二)
------------------------------------------------------------------------
-- Author : HappyFlyStone
-- Date : 2009-09-27 21:36:30
-- Version: Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86)
-- Apr 14 2006 01:12:25
-- Copyright (c) 1988-2005 Microsoft Corporation
-- Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
-- 轉載請註明出處,更多請關注:http://blog.csdn.net/happyflystone
-- 關鍵字:隔離等級 鎖定
------------------------------------------------------------------------
四、隔離等級
首先來說說隔離,隔離是一個事務必須與其他事務所進行的資源或數據更改相隔開,顯然隔離等級就是相隔的程度了吧。在說隔離級別不得不提及鎖的概念,但是在本單不提及鎖,在以後聽章節裏再作說明,大家只要有個印象就行。在這兒我們必須明白兩件事:
1,隔離級別不會影響進程獲得數據修改的排它鎖,並且這個鎖會保存到事務結束。相對於讀進程來說,隔離級別就是對讀操作的一個保護級別,保護讀操作受其它事務影響的程序。
2,較低的隔離級別可以增強許多用戶同時訪問數據的能力,但也增加了用戶可能遇到的併發副作用(例如髒讀或丟失更新)的數量。相反,較高的隔離級別減少了用戶可能遇到的併發副作用,卻需要太多的系統資源及一個事務阻塞其他事務的可能性。
應平衡應用程序的完整性要求與相應隔離級別的系統開銷,在此基礎上選擇相應的隔離級別。最高隔離級別(可序列化)保證事務在每次重複讀取操作時都能準確檢索到相同的數據,但需要通過執行某種級別的鎖定來完成此操作,而鎖定可能會影響其他用戶進程。最低隔離級別(未提交讀)可以檢索其他事務已經修改但未提交的數據。在未提交讀中,所有併發副作用都可能發生,但因爲沒有讀鎖定或修改阻塞讀取,所以開銷最少。
不同的隔離級別決定我們有哪些數據副作用可以發生,而併發模型決定不同隔離等級下如何來限制這些數據行爲或如何協調這數據行爲。好,那我們來關注一下不同隔離等級下如何限制這些行爲的發生。
未提交讀(uncommitted Read):字面理解一下,修改了的未提交數據可以讀取。準確點:一個用戶進程可以讀取另一個用戶進程修改卻未提交的數據。SQL SERVER對這個等級下的讀操作不需要獲得任何鎖就可以讀取數據,因爲不需要鎖所以不會和其它任何進程互相阻塞,自然而然能讀取其它進程修改了的卻未提交數據。顯然這不是我們理想的一種模式,但是它卻有了高併發性,因爲讀操作沒有鎖不會影響其它進程的讀或寫操作。在這種級別下,除了丟失更新(上一講中的數據可能發生的行爲)外,其它行爲都有可能發生,冒着數據不一致的風險來避免修改的進程阻塞讀取的進程,事務的一致性肯定是得不到保障,顯然這是消極併發模式下的迴避阻塞頻繁的一種解決方案。未提交讀那肯定是不適合於股票、金融系統的,但是在一些趨勢分析的系統裏,要求的只是一種走向,準確性可以不是那麼嚴格時,這個級別因併發性能超強成爲首選。
已提交讀(Read Committed):它和未提交讀相反,已提交讀級別保證一個進程不可能讀到另一個進程修改但未提交的數據。這個級別是引擎默認的級別,也是2005樂觀併發模式下支持的級別,也就是說已提交讀可是樂觀的也可以是悲觀的,那究竟當前庫是屬於哪個併發模型下的已提交讀呢,這取決於一個READ_COMMITED_SNAPSHOT數據庫配置項,並且缺省是悲觀併發控制的。這個配置項決定已提交讀級別下事務使用鎖定還是行版本控制,並很顯然行版本控制是樂觀併發模式,鎖定是悲觀併發模式。我們來點角本看看:
--設置已提交讀隔離使用行版本控制
ALTER DATABASE testcsdn SET READ_COMMITTED_SNAPSHOT ON
GO
--查看當前已提交讀隔離併發模型
select name,database_id,is_read_committed_snapshot_on from sys.databases
/*
name database_id is_read_committed_snapshot_on
-------------------- ----------- -----------------------------
master 1 0
tempdb 2 0
model 3 0
msdb 4 0
ReportServer$SQL2005 5 0
ReportServer$SQL2005TempDB 6 0
TestCsdn 7 1 --current
(7 行受影響)
*/
--設置已提交讀隔離使用鎖定
ALTER DATABASE testcsdn SET READ_COMMITTED_SNAPSHOT OFF
GO
--查看已提交讀隔離併發模型
select name,database_id,is_read_committed_snapshot_on from sys.databases
/*
name database_id is_read_committed_snapshot_on
-------------------- ----------- -----------------------------
master 1 0
tempdb 2 0
model 3 0
msdb 4 0
ReportServer$SQL2005 5 0
ReportServer$SQL2005TempDB 6 0
TestCsdn 7 0 --curret
(7 行受影響)
*/
已提交讀在邏輯上保證了不會讀到不實際存在的數據。悲觀併發下的已提交讀,當進程要修改數據時會在數據行上申請排它鎖,其它進程(無論是讀還是寫)必須等到排它鎖釋放纔可以使用這些數據。如果進程僅是讀取數據時會使用共享鎖,其它進程雖然可以讀取數據但是無法更新數據,必須等到共離鎖釋放(共享鎖在數據處理完即釋放,比如行共享鎖在當前數據行數據處理完就自動釋放,不會在整個事務內保留髮。)。樂觀併發的已提交讀,也確保不會讀到未提交的數據,不是通過鎖定的方式來實現,而是通過行版本控制器生成行的提前交的數據版本,被修改的數據雖然仍然鎖定,但是其它進程可以可以讀取更新前版本數據。
可重複讀(Repeatable Read):這也是一個悲觀併發的級別。可重複讀比已提交讀要求更嚴格,在已提交讀的基礎上增加了一個限制:獲取的共享鎖保留到事務結束。在這個限制下,進程在一個事務裏兩交次讀取的數據一致,也就是不會讀取到其它進程修改了數據。在這兒我們提到共享鎖會保留到事務結束,那得申明一下無論哪種級別及併發模型,排它鎖是一定要保留到事務結束的。在可重複讀級別共享鎖同樣也會保留到事務結束。那麼這種對數據安全的保證是通過增加共享保留的開銷爲代價的,也就是隻要開始一個事務,其它用戶進程是不可能修改數據的,顯而易見的系統的併發性和性能必然下降。這似乎是我們想像中的一種級別,雖然這個級別暫時無法迴避幻影讀,而且我們也默許併發及性能下降,那只有對程序員對事務的控制有嚴格的要求:事務要短並儘量不要人爲因素的干擾,減少潛在的鎖競爭。
快照(SnapShot):樂觀併發級別。這是2005新增加的一個隔離級別。快照級別與使用樂觀併發的已提交讀差不多,差別在於行版控制器裏的數據版本有多早,這個在以後講鎖時再說。這個級別保證了一個事務讀取的數據是事務開始時就在數據庫邏輯上確認並符合一致性的數據。讀操作不會要求共享鎖定,如果要求的數據已經排它,就會通過行版本控制器讀取最近的符合一致性的數據。
可串行化:是目前最嚴謹、最健壯的一個級別,屬於悲觀併發。它防止幻影的發生,迴避了以前所有意外行爲的發生。可串行化意味着系統按進程進入隊列的順序依次、序列化的執行的結果與事務同時運行得到一致的結果。這個最健壯的級別顯然共享鎖也是隨事務開始隨事務結束,並通過鎖定部分不存在的數據(即索引鍵範圍鎖定)來回避幻影的發生。
今天的任務完成,前兩篇我只是把理論上的東西整理了一下,下一篇我把意外行爲結合隔離等級用點實例來說明,然後再開始整理鎖定。
請大家繼續關注我的blog: http://blog.csdn.net/happyflystone