天天看點

SQL2005中的事務與鎖定(二)

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

--設定已送出讀隔離使用鎖定

ALTER DATABASE testcsdn SET READ_COMMITTED_SNAPSHOT OFF

GO

--檢視已送出讀隔離并發模型

select name,database_id,is_read_committed_snapshot_on  from sys.databases

已送出讀在邏輯上保證了不會讀到不實際存在的資料。悲觀并發下的已送出讀,當程序要修改資料時會在資料行上申請排它鎖,其它程序(無論是讀還是寫)必須等到排它鎖釋放才可以使用這些資料。如果程序僅是讀取資料時會使用共享鎖,其它程序雖然可以讀取資料但是無法更新資料,必須等到共離鎖釋放(共享鎖在資料處理完即釋放,比如行共享鎖在目前資料行資料處理完就自動釋放,不會在整個事務内保留發。)。樂觀并發的已送出讀,也確定不會讀到未送出的資料,不是通過鎖定的方式來實作,而是通過行版本控制器生成行的提前交的資料版本,被修改的資料雖然仍然鎖定,但是其它程序可以可以讀取更新前版本資料。

可重複讀(Repeatable Read):這也是一個悲觀并發的級别。可重複讀比已送出讀要求更嚴格,在已送出讀的基礎上增加了一個限制:擷取的共享鎖保留到事務結束。在這個限制下,程序在一個事務裡兩交次讀取的資料一緻,也就是不會讀取到其它程序修改了資料。在這兒我們提到共享鎖會保留到事務結束,那得申明一下無論哪種級别及并發模型,排它鎖是一定要保留到事務結束的。在可重複讀級别共享鎖同樣也會保留到事務結束。那麼這種對資料安全的保證是通過增加共享保留的開銷為代價的,也就是隻要開始一個事務,其它使用者程序是不可能修改資料的,顯而易見的系統的并發性和性能必然下降。這似乎是我們想像中的一種級别,雖然這個級别暫時無法回避幻影讀,而且我們也默許并發及性能下降,那隻有對程式員對事務的控制有嚴格的要求:事務要短并盡量不要人為因素的幹擾,減少潛在的鎖競争。

快照(SnapShot):樂觀并發級别。這是2005新增加的一個隔離級别。快照級别與使用樂觀并發的已送出讀差不多,差别在于行版控制器裡的資料版本有多早,這個在以後講鎖時再說。這個級别保證了一個事務讀取的資料是事務開始時就在資料庫邏輯上确認并符合一緻性的資料。讀操作不會要求共享鎖定,如果要求的資料已經排它,就會通過行版本控制器讀取最近的符合一緻性的資料。

可串行化:是目前最嚴謹、最健壯的一個級别,屬于悲觀并發。它防止幻影的發生,回避了以前所有意外行為的發生。可串行化意味着系統按程序進入隊列的順序依次、序列化的執行的結果與事務同時運作得到一緻的結果。這個最健壯的級别顯然共享鎖也是随事務開始随事務結束,并通過鎖定部分不存在的資料(即索引鍵範圍鎖定)來回避幻影的發生。

今天的任務完成,前兩篇我隻是把理論上的東西整理了一下,下一篇我把意外行為結合隔離等級用點執行個體來說明,然後再開始整理鎖定。

請大家繼續關注我的blog: http://blog.csdn.net/happyflystone