SQL2005中的事務與鎖定(一)
------------------------------------------------------------------------
-- Author : HappyFlyStone
-- Date: 2009-09-24 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)
--關鍵字:LOCKConcurrency 鎖 事務 併發
------------------------------------------------------------------------
終於定下心來寫這個事務與鎖定的文章,下筆後才發現真的很難寫,交易中事務與鎖定這個話題過於複雜,甚至有些還摸不著(就是通過DMV或DMF或其它工具你可能很難看到它的蹤影),讓人有點讓人望而止步,但是既然說了要寫,似乎不繼續下去不是我的風格。在接下來的幾篇文章(其實我也不知道要幾篇)裡我就事務與鎖定這個話題寫寫,由SQL2005的併發模型引入事務,在事務的概念裡展開鎖定,本著先概念後例項的原則,和大家一起來學習,有不當之處希望大家指正。
一、併發及併發控制模型
對於這個我在<<SQL2005資料庫引擎結構>>一文有所提及,你可以通過如下連結進行訪問:
並有一起的意思,顯然就是多個的意思啦,光書面來理解併發就是多個東西同時發生,在資料庫併發就是多個程序同時取、存資料庫裡資料的能力。著眼我們開發的系統,當然是激動態的並互不打架的併發使用者程序越多併發能力就越強大啦,你想想看好多的網上購物系統,如果沒有併發處理的能力,那麼在上面登記的使用者資訊、商品有庫存資訊及使用者帳戶資訊很難保證正確性和一致性,比如一個物品本身庫存只有100個,結果如果100人同時線上進行預定,庫存就有可能搞一個100-1的效果出來。
很顯然對上述的例子我們希望一個程序在修改庫存資料時必須阻止其它程序讀或修改資料,或是正在讀的使用者程序限制其它活動的使用者程序進行讀或修改的操作,這樣一來勢必造成系統的併發效能下降,但是如果不採用這種辦法又無法保證資料正確性和一致性。那怎麼解決這個問題呢,辦法只有通過不同的併發模式
併發控制模式:一般併發控制模式有兩種:積極併發(又稱樂觀併發)和消極併發(又稱悲觀併發)。積極併發是SQL2005才引入的新模式,在2005以前的版本其實只有唯一的併發模式即:消極併發。那什麼是消極併發呢?消極併發就是SQLSERVER預設行為是程序以獲取鎖的方式來阻止其它程序對正在使用的資料進行修改的能力。對於資料庫來說對資料修改的操作程序肯定很多,這些程序肯定都會去影響其它程序讀取資料的能力,反之,對資料進行讀時加上鎖也一定會影響其它程序修改資料的能力,簡而言之,就是讀取與修改資料之間是衝突的、互相阻塞的。樂觀併發是SQL2005利用一個行版本控制器的新技術來處理上述的衝突。行版本控制器在當前程序讀取資料時生成舊版本的資料,使得其它請求讀的程序能看到當前程序一開始讀取時的資料狀態,並且不受當前程序或其它程序對資料進行修改的影響。簡而言之讀與修改之間是不衝突的,但是修改與修改之間還是衝突的。
對於這兩種併發模式兩個程序同時請求資料修改必然會衝突的,除此以外的差別在於一個是在衝突發生前進行控制,另一個在衝突發生了進行協調處理。這好比生活一樣,兩種方式就是兩種不同的人生,一種消極怠工一種積極向上。
二、併發下可能發生的併發副作用:丟失更新、髒讀、不可重複讀、幻影。
為了把這些可能發生的併發副作用說清楚,我們先“佈置”一個場景:這是一個賣工藝石頭的小商店,平時在前場完成交易,客戶憑單據到後場領取石頭,AMM和BMM是營業員,她們平時掌握庫存數是通過大廳裡的一塊LED顯示牌得之,並且在各自完成一筆交易後修改LED顯示,以保證資料的實時性。在這個場景下我們來觀察可能發生的行為:
1、丟失更新:
丟失更新估計是所有資料庫使用者都不想發生的情況,什麼是丟失更新呢?丟失更新是當2個或兩個以上的使用者程序同時讀取同樣的資料後又企圖修改原來的資料時就會發生。好在上述場景下,大廳LED顯示牌顯示當前庫存1000,這時同時有兩個客戶上門了,AMM和BMM滿面春風接待,比如AMM賣出1個,BMM呢賣出了10個,AMM處理完業務後趕緊把LED顯示數修改為1000 - 1 = 999個,幾乎同一時間BMM處理完自己的業務後習慣性的把LED顯示數修改為1000 - 10 = 990 個,這時老闆從後場過來,看著LED有點不爽,大吼一聲:現在還有多少存貨呀?,AMM說我賣了1個,BMM說我是10個,不過兩個人都傻眼了,LED顯示怎麼是990呢?原來BMM在更改時把AMM做的更改搞丟了,這就是丟失更新。顯然對老闆和營業員來說都是必須迴避不能發生的事。
2、髒讀
很顯然,在上面的例子裡因為AMM和BMM事先因為不知道對方已經修改了櫃檯存貨,所以才造成了存貨數目顯示錯誤,出了問題我們要想辦法解決問題,英明的老闆說了,你們隨便哪個在談一筆生意時先把客戶意向購賣石頭數扣掉,如果最後客戶不要你再改回頭,兩個MM對老闆的英明決定表示等贊同,可是問題還是發生了,怎麼回事呢,還是假設櫃臺存貨1000個石頭,AMM有一筆生意正在談著,顧客意向要600塊石頭,AMM趕緊把LED顯示修改為400。這時BMM也很興奮因為她已經談成一筆700塊石頭的生意,所以呢BMM擡頭一看,好嘛,還有400塊可賣,完了BMM的生意做不成了,只好向客戶表達歉意。BMM只能讓老闆進貨,可是老闆一看LED顯示還有1000塊怎麼你的700塊生意做不成了呢?哦,因為最後AMM的600塊生意沒做成。嘿嘿,也就是BMM錯誤的讀取了AMM修改的資料,完成了一次“髒讀”操作。髒讀也就是一個使用者程序讀取了另一個使用者程序修改過但沒有正式提交的資料,這時導致了資料不一樣的情形發生了。因為A使用者程序是無法確認另一個B使用者程序在自己提交資料前是否修改過資料,這是資料庫系統預設情況下必須迴避的。
3、不可重複讀
不可重複讀又稱不一致分析,不過,個人以為似乎不一致分析更讓人好理解一點,但是大部分地方稱不可重複讀。不可重複讀是指一個使用者程序兩次讀取資料得到不同樣的資料。比如那個英明的老闆吧,他知道要盤點,掌握庫存的變化,忙得満頭大汗,終於計出庫存數來,比如說1000吧,或是當他跑到大廳一看LED顯示牌卻只有了900,顯然這一次的檢查庫存的過程中兩次得到庫存數不一樣,原因就是AMM在老闆從後場走到前場的過程中做了一擔生意,賣出100塊。嘿嘿,老闆氣又不是不氣又不是,這AMM真可愛,做生意挺兩下呀!顯然在一個使用者程序兩次讀取資料間隔內另一個使用者程序修改了資料,這就是不可重複讀。
4、幻影
幻影,嘿嘿,我們不是經常無視BS自己的人嗎?你無視他並不代表他不BS你吧,這個BS你的人就成了幻影,嘿嘿開個玩笑。這種情況多數在查詢帶謂詞時結果集內部分資料變化的時候發生,如果謂詞限定下在一個交易裡兩次同一查詢的結果集不同,那些不同的行或行集就是幻影。比方說英明的老闆到大廳走走,順便請大家吃飯,數數人數,BMM,。。。。一路數過去,發現有10人,呵呵,正好一桌,,通知好她們後老闆回辦會室拿人民幣,回到前場看見AMM,再一數11人,暈,剛才怎麼看到AMM ?AMM也知道了老闆請客沒數到他,很是生氣,這時AMM就成了幻影。
以上是四種併發副作用只是一個交易事務裡或事務間可能發生的異常的非一致的資料行為(記好併發副作用和不一致的資料行為術語,這在以後會經常提及),其實還是有好多的行為是我們所期望的,那麼我們期望的行為是什麼呢,下面我們在事務裡來介紹。我們可以通過隔離級別來設定一個合適級別以決定上述上種資料行為哪些是允許的。那什麼是交易事務,什麼又是隔離等級呢?
三、事務
事務是資料庫一筆交易的基本單元,存於兩種併發模型中。又分為顯式事務和隱式事務。顯式事務是顯式的開始一個事務並顯式的滾回或提交事務,除了顯式的事務還有隱式的了,隱式事務是資料庫自己根據情況完成的事務處理,如單獨的select、update、delete、select語句。
作為一個事務,它能保證資料庫的資料一致性及重做。提到事務不得不提及事務的ACID屬性:原子性、一致性、隔離性及永續性。不管是顯式還是隱式的,都必須維持這四個屬性。
原子性:一個事務是一個整體,要不全部提交,要不全部中止。意思就是要不全部成功提交到資料,要不全部回滾恢復事務開始前的狀態。比方我們做一個入庫操作,在這個事務裡,稽核入庫單和修改庫存作為一個整體,要不單據變成稽核過同時庫存增加相應的值,要不就是單據未稽核同時庫存不變。
一致性:一致性要求事務保證資料在邏輯上正確,處理的結果不是一個不確定的狀態,什麼是不確定狀態呢,比如說我們完成一個庫存減少的操作,如果沒有一個出貨單據那麼這個庫存的當前修改就是一個不確定狀態,因為你無法知道減少的東東到哪兒去了。
隔離性:這個隔離和鎖定有關,以後在說鎖的過程中會提到這些,你先記住這個就行。
永續性:持久很顯然是要求正確提交的修改必須保證長久存在,不會因為關機或掉電把這筆交易丟掉。進行中的事務發生故障那事務就完全撤銷,像沒有發生一樣,如果事務提交的確認已經反饋給應用程式發生故障,那麼這些日誌利用先寫技術,在啟動恢復階段自動完成相應的動作保證事務的永續性。(這個在前面的引擎元件有過介紹哦。)