亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SQL?Server中鎖的用法

 更新時間:2022年05月20日 11:31:53   作者:springsnow  
這篇文章介紹了SQL?Server中鎖的用法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

鎖是一種防止在某對象執(zhí)行動作的一個進程與已在該對象上執(zhí)行的其他進行相沖突的機制。也就是說,如果有其他人在操作某個對象,那么你舊不能在該對象上進行操作。你能否執(zhí)行操作取決于其他用戶正在進行的操作。

通過鎖可以防止的問題

鎖可以解決以下4種主要問題:

1、臟讀

如果一個事務讀取的記錄是另一個未完成事務的一部分,那么這時就發(fā)生了臟讀。如果第一個事務正常完成,那么就有什么問題。但是,如果前一個事務回滾了呢,那將從數(shù)據(jù)庫從未發(fā)生的事務中獲取了信息。

2、非重復性讀取

很容易將非重復性讀取和臟讀混淆。如果一個事務中兩次讀取記錄,而另一個事務在這期間改變了數(shù)據(jù),就會發(fā)生非重復性讀取。
例如,一個銀行賬戶的余額是不允許小于0的。如果一個事務讀取了某賬戶的余額為125元,此時另一事務也讀取了125元,如果兩個事務都扣費100元,那么這時數(shù)據(jù)庫的余額就變成了-75元。

有兩種方式可以防止這個問題:

  • 創(chuàng)建CHECK約束并監(jiān)控547錯誤
  • 將隔離級別設置為REPEATABLEREAD或SERIALIZABLE

CHECK約束看上去相當直觀。要知道的是,這是一種被動的而非主動的方法。然而,在很多情況下可能需要使用非重復性讀取,所以這在很多情況下是首選。

3、幻讀

幻讀發(fā)生的概率非常小,只有在非常偶然的情況下才會發(fā)生。

比如,你想將一張工資表里所有低于100的人的工資,提高到100元。你可能會執(zhí)行以下SQL語句:

UPDATE tb_Money SET Salary = 100
WHERE Salary < 100

這樣的語句,通常情況下,沒有問題。但是如果,你在UPDATE的過程中,有人恰好有INSERT了一條工資低于100的數(shù)據(jù),因為這是一個全新的數(shù)據(jù)航,所以沒有被鎖定,而且它會被漏過Update。

要解決這個問題,唯一的方法是設定事務隔離級別為SERIALIZABLE,在這種情況下,任何對表的更新都不能放入WHERE子句中,否則他們將被鎖在外面。

4、丟失更新

丟失更新發(fā)生在一個更新成功寫入數(shù)據(jù)庫后,而又意外地被另一個事務重寫時。這是怎么發(fā)生的呢?如果有兩個事務讀取整個記錄,然后其中一個向記錄寫入了更新信息,而另一個事務也向該記錄寫入更新信息,這是就會出現(xiàn)丟失更新。

有個例子寫得很好,這里照敲下來吧。假如你是公司的一位信用分析員,你接到客戶X打開的電話,說他已達到它的信用額度上限,想申請增加額度,所以你查看了這位客戶的信息,你發(fā)現(xiàn)他的信用額度是5000,并且看他每次都能按時付款。

當你在查看的時候,信用部門的另一位員工也讀取了客戶X的記錄,并輸入信息改變了客戶的地址。它讀取的記錄也顯示信用額度為5000。

這時你決定把客戶X的信用額度提高到10000,并且按下了Enter鍵,數(shù)據(jù)庫現(xiàn)在顯示客戶X的信用額度為10000。

Sally現(xiàn)在也更新了客戶X的地址,但是她仍然使用和您一樣的編輯屏幕,也就是說,她更新了整個記錄。還記得她屏幕上顯示的信用額度嗎?是5000.數(shù)據(jù)庫現(xiàn)在又一次顯示客戶X的信用額度為5000。你的更新丟失了。

解決這個問題的方法取決于你讀取某數(shù)據(jù)和要更新數(shù)據(jù)的這段時間內,代碼以何種方式識別出另一連接已經更新了該記錄。這個識別的方式取決于你所使用的訪問方法。

可以鎖定的資源

對于SQL Server來說,有6種可鎖定的資源,而且它們形成了一個層次結構。鎖的層次越高,它的粒度就越粗。按粒度由粗到細排列,這些資源包括:

  • 數(shù)據(jù)庫:鎖定整個數(shù)據(jù)庫。這通常發(fā)生在整個數(shù)據(jù)庫模式改變的時候。
  • 表:鎖定整個表。這包含了與該表相關聯(lián)的所有數(shù)據(jù)相關的對象,包括實際的數(shù)據(jù)行(每一行)以及與該表相關聯(lián)的所有索引中的鍵。
  • 區(qū)段:鎖定整個區(qū)段。因為一個區(qū)段由8頁組成,所以區(qū)段鎖定是指鎖定控制了區(qū)段、控制了該區(qū)段內8個數(shù)據(jù)或索引頁以及這8頁中的所有數(shù)據(jù)航。
  • 頁:鎖定該頁中的所有數(shù)據(jù)或索引鍵。
  • 鍵:在索引中的特定鍵或一系間上有鎖。相同索引頁中的其他鍵不受影響。
  • 行或行標識符:雖然從技術上將,鎖是放在行標識符上的,但是本質上,它鎖定了整個數(shù)據(jù)行。

鎖升級和鎖對性能的影響

升級是指能夠認識到維持一個較細的粒度(例如,行鎖而不是頁鎖),只在被鎖定的項數(shù)較少時有意義。而隨著越來越多的項目被鎖定,維護這些鎖的系統(tǒng)開銷實際上會影響性能。這會導致所持續(xù)更長的時間。

當維持鎖的數(shù)量達到一定限度時,則鎖升級為下一個更高的層次,并且將不需要再如此緊密地管理低層次的鎖(釋放資源,而且有助于提升速度)。

注意,升級是基于鎖的數(shù)量,而不是用戶的數(shù)量。這里的重點是,可以通過執(zhí)行大量的更新來單獨地鎖定表-行鎖可以升級為頁鎖,頁鎖可以升級為表鎖。這意味著可能將所有其他用戶鎖在該表之外。如果查詢使用了多個表,則它很可能將每個人鎖在這些表之外。

鎖定模式

除了需要考慮鎖定的資源層次以外,還要考慮查詢將要獲得的鎖定模式,就像需要對不同的資源進行鎖定一樣,也有不同的鎖定模式。一些模式是互相排斥的。一些模式什么都不做,只修改其他的模式。模式是否可以一起使用取決于他們是否是兼容的。

1、共享鎖

這是最基本的一種鎖。共享鎖用于只需要讀取數(shù)據(jù)的時候,也就是說,共享鎖鎖定時,不會進行改變內容的操作,其他用戶允許讀取。

共享鎖能和其他共享鎖兼容。雖然共享鎖不介意其他鎖的存在,但是有些鎖并不能和共享鎖共存。

共享鎖告訴其他鎖,某用戶已經在那邊了,它們并不提供很多的功能,但是不能忽略它們。然而,共享鎖能做的是防止用戶執(zhí)行臟讀。

2、排它鎖

排它鎖顧名思義,排它鎖不與其他任何鎖兼容。如果有任何其他其他鎖存在,則不能使用排他鎖,而且當排他鎖仍然起作用時,他們不允許在資源之上創(chuàng)建任何形式的新鎖。這可以防止兩個人同時更新、刪除或執(zhí)行任何操作。

3、更新鎖

更新鎖是共享鎖和排他鎖的混合。更新鎖是一種特殊的占位符。為了能執(zhí)行UPDATE,需要驗證WHERE子句來指出想要更新的具體的數(shù)據(jù)行。這意味著只需要一個共享鎖,直到真正地進行物理更新。在物理更新期間,需要一個排他鎖。

  • 第一個階段指出了滿足WHERE子句條件的內容,這是更新查詢的一部分,該查詢有一個更新鎖。
  • 第二個階段是如果決定執(zhí)行更新,那么鎖將升級為排他鎖。否則,將把鎖轉換為共享鎖。

這樣做的好處是它防止了死鎖。死鎖本身不是一種鎖定類型,而是一種已經形成矛盾的狀況,兩個鎖在互相等待,多個鎖形成一個環(huán)在等待前面的事務清除資源。

如果沒有更新鎖,死鎖會一直出現(xiàn)。兩個更新查詢會在共享模式下運行。Query A完成了它的查詢工作并準備進行物理更新。它想升級為排他鎖,但是不可以這么做,因為Query B正在完成查詢。除非Query B需要進行物理更新,否則它會完成查詢。為了做到這點,Query B必須升級為排他鎖,但是不能這么做,因為Query A正在等待。這樣就造成了僵局。

而更新鎖阻止建立其他的更新鎖。第二個事務只要嘗試取得一個更新鎖,它們就會進入等待狀態(tài),直到超時為止-將不會授予這個鎖。如果第一個鎖在鎖超時之前清除的話,則鎖定會授予給新的請求者,并且這個處理會繼續(xù)下去。如果不清楚,則會發(fā)生錯誤。

更新鎖只與共享鎖以及意向共享鎖相兼容。

4、意向鎖

意向鎖是什么意思呢?就是說,加入你鎖定了某一行,那么同時也加了表的意向鎖(不允許其他人通過表鎖來妨礙你)。

意向鎖是真正的占位符,它用來處理對象層次問題的。假設一下如下情況:已對某一行建立了鎖,但是有人想在頁上或區(qū)段上建立所,或者是修改表。你肯定不想讓另一個事務通過達到更高的層次來妨礙你。
如果沒有意向鎖,那么較高層次的對象將不會知道在較低層次上有鎖。意向鎖可改進性能,因為SQL Server只需要在表層次上檢查意向鎖(而不需要檢查表上的每個行鎖或者頁鎖),以此來決定事務是否可以安全地鎖定整個表。

意向鎖分為以下3種不同的類型:

  • 意向共享鎖:該意向鎖指已經或者將要在層次結構的一些較低點處建立共享鎖。
  • 意向排他鎖:它與意向共享鎖一樣,但是將會在低層項上設置排他鎖。
  • 共享意向排他鎖:它指已經或將會在對象層次結構下面建立共享鎖,但目的是為了修改數(shù)據(jù),所以它會在某個時刻成為意向排它鎖。

5、模式鎖

模式鎖分為以下兩種。

  • 模式修改鎖:對對象進行模式改變。在Sch-M鎖期間,不能對對象進行查詢或其他CREATE、ALTER或DROP語句的操作。
  • 模式穩(wěn)定鎖鎖定:它和共享鎖很相似;這個鎖的唯一目的是方式模式修改鎖,因為在該對象上已有其他查詢(或CREATE、ALTER、DROP語句)的鎖。它與其他所有的鎖定相兼容。

6、批量更新鎖

批量更新鎖(BU)只是一種略有不同的表鎖定變體形式。批量更新鎖允許并行加載數(shù)據(jù)。也就是說,對于其他任何普通操作(T-SQL)都會將表鎖定,但可以同時執(zhí)行多個BULK INSERT或bcp操作。

鎖的兼容性

鎖的資源鎖定模式的兼容性表格,現(xiàn)有鎖以列顯示,要兼容的鎖以行顯示。

鎖的類型意向共享鎖(IS)共享鎖(S)更新鎖(U)意向排他鎖(IX)共享意向排它鎖(SIX)排他鎖(X)
意向共享鎖(IS)
共享鎖(S)
更新鎖(U)
意向排他鎖(IX)
共享意向排它鎖(SIX)
排他鎖(X)

另外:

  • Sch-S與出Sch-M以外的所有鎖定模式相兼容。
  • Sch-M和所有的鎖定模式不兼容。
  • BU只與模式穩(wěn)定性鎖以及其他的批量更新鎖相兼容。

有時想要在查詢中或在整個事務中對鎖定有更多的控制??梢酝ㄟ^使用優(yōu)化器提示(optimizer hints)來實現(xiàn)這一點。

優(yōu)化器提示明確告訴SQL Server將一個鎖升級為特有的層次。這些提示信息包含在將要影響的表的名稱之后。

優(yōu)化器提示是一個高級主題,有經驗的SQL Server開發(fā)人員會經常使用它,并且他們相當重視它。

使用Management Studio確定鎖

查看鎖的最好方式是使用Management Studio。通過使用Activity Monitor,Management Studio會以兩種方式顯示鎖-通過processId或object。

為了使用Management Studio顯示鎖,只要導航到<Server>的Activity Monitor節(jié)點,其中的<Server>是監(jiān)控其活動的服務器的頂級節(jié)點。

展開感興趣的節(jié)點(Overview部分默認展開),可以通過滾動條查看大量度量值-包括當前系統(tǒng)中有效的鎖。

顯示界面如下:

設置隔離級別

事務和鎖之間的聯(lián)系是很緊密的。默認情況下,一旦創(chuàng)建了任何與數(shù)據(jù)修改相關的鎖,該鎖定就會在整個事務期間存在。如果有一個大型事務,就意味著將在很長一段時間內阻止其他進程訪問鎖定的對象。這明顯是有問題的。

事務有5種隔離級別:

  • READ COMMITTED
  • READ UNCOMMITTED
  • REPEATABLE READ
  • SERIALIZABLE
  • SNAPSHOT

在這些隔離級別之間進行切換的語法也相當直觀:

SET TRANSACTION ISOLATION LEVEL < READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE | SNAPSHOT >

對隔離級別的修改只會影響到當前的連接-所以不必擔心會影響到其他的用戶。其他用戶也影響不了你。

1、READ COMMITTED

默認情況就是這個,通過READ COMMITTED,任何創(chuàng)建的共享鎖將在創(chuàng)建它們的語句完成后自動釋放。也就是說,如果啟動了一個事務,運行了一些語句,然后運行SELECT語句,再運行一些其他的語句,那么當SELECT語句完成的時候,與SELECT語句相關聯(lián)的鎖就會釋放 - SQL Server并不會等到事務結束。

動作查詢(UPDATE、DELETE、INSERT)有點不同。如果事務執(zhí)行了修改數(shù)據(jù)的查詢,則這些鎖將會在事務期間保持有效。

通過設置READ COMMITTED這一默認隔離級別,可以確定有足夠的數(shù)據(jù)完整性來防止臟讀。然而,仍會發(fā)生非重復性讀取和幻讀。

2、READ UNCOMMITTED

READ UNCOMMITTED是所有隔離級別中最危險的,但是它在速度方面有最好的性能。
設置隔離級別為READ UNCOMMITTED將告訴SQL Server不要設置任何鎖,也不要事先任何鎖。
鎖既是你的保護者,同時也是你的敵人。鎖可以防止數(shù)據(jù)完整性問題,但是鎖也經常妨礙或阻止你訪問需要的數(shù)據(jù)。由于此鎖存在臟讀的危險,因此此鎖只能應用于并非十分精確的環(huán)境中。

3、REPEATABLE READ

REPEATABLE READ會稍微地將隔離級別升級,并提供一個額外的并發(fā)保護層,這不僅能防止臟讀,而且能防止非重復性讀取。
防止非重復性讀取是很大的優(yōu)勢,但是直到事務結束還保持共享鎖會阻止用戶訪問對象,因此會影響效率。推薦使用其他的數(shù)據(jù)完整性選項,例如CHECK約束,而不是采用這個選擇。
與REPEATABLE READ隔離級別等價的優(yōu)化器提示是REPEATABLEREAD(除了一個空格,兩者并無不同)。

4、SERIALIZABLE

SERIALIZABLE是堡壘級的隔離級別。除了丟失更新以外,它防止所有形式的并發(fā)問題。甚至能防止幻讀。

如果設置隔離級別為SERIALIZABLE,就意味著對事物使用的表進行的任何UPDATE、DELETE、INSERT操作絕對不滿足該事務中任何語句的WHERE子句的條件。從本質上說,如果用戶想執(zhí)行一些事務感興趣的事情,那么必須等到該事務完成的時候。

SERIALIZABLE隔離級別也可以通過查詢中使用SERIALIZABLE或HOLDLOCK優(yōu)化器提示模擬。再次申明,類似于READ UNCOMMITTED和NOLOCK,前者不需要每次都設置,而后者需要把隔離級別設置回來。

5、SNAPSHOT

SNAPSHOT是最新的一種隔離級別,非常想READ COMMITTED和READ UNCOMMITTED的組合。要注意的是,SNAPSHOT默認是不可用的-只有為數(shù)據(jù)庫打開了ALLOW_SNAPSHOT_ISOLATION特殊選項時,SNAPSHOT才可用。
和READ UNCOMMITED一樣,SNAPSHOT并不創(chuàng)建任何鎖,也不實現(xiàn)人和所。兩者的主要區(qū)別是它們識別數(shù)據(jù)庫中不同時段發(fā)生的更改。數(shù)據(jù)庫中的更改,不管何時或是否提交,都會被運行READ UNCOMMITTED隔離級別的查詢看到。而使用SNAPSHOT,只能看到在SNAPSHOT事務開始之前提交的更改。從SNAPSHOT事務一開始執(zhí)行,所有查看到的數(shù)據(jù)就和在時間開始時提交的一樣。

處理死鎖

死鎖的錯誤號是1205。

如果一個鎖由于另一個鎖占有資源而不能完成應該做的清除資源工作,就會導致死鎖;反之亦然。當發(fā)生死鎖時,需要其中的一方贏得這場斗爭,所以SQL Server選擇一個死鎖犧牲者,對死鎖犧牲者的事務進行回滾,并且通過1205錯誤來通知發(fā)生了死鎖。另外一個事務將繼續(xù)正常地運行。

1、判斷死鎖的方式

每隔5秒鐘,SQL Server就會檢查所有當前的事務,了解他們在等待什么還未被授予的鎖。然后再一次重新檢查所有打開的鎖請求的狀態(tài),如果先前請求中有一個還沒有被授予,則它會遞歸地檢查所有打開的事務,尋找鎖定請求的循環(huán)鏈。如果SQL Server找到這樣的村換連,則將會選擇一個或更多的死鎖犧牲者。

2、選擇死鎖犧牲者的方式

默認情況下,基于相關事務的"代價",選擇死鎖犧牲者。SQL Server將會選擇回滾代價最低的事務。在一定程度上,可以使用SQL Server中的DEADLOCK_PRIORITY SET選項來重寫它。

3、避免死鎖

避免死鎖的常用規(guī)則

  • 按相同的順序使用對象
  • 使事務盡可能簡短并且在一個批處理中。
  • 盡可能使用最低的事務隔離級別。
  • 在同一事務中不允許無限度的中斷。
  • 在控制環(huán)境中,使用綁定連接。

1、按相同的順序使用對象

例如有兩個表:Suppliers和Products。假設有兩個進程將使用這兩個表。進程1接受庫存輸入,用手頭新的產品總量更新Products表,接下來用已經購買的產品總量來更新Suppliers表。進程2記錄銷售數(shù)據(jù),它在Supperlier表中更新銷售產品的總量,然后在Product中減少庫存數(shù)量。

如果同時運行這兩個進程,那么就有可能碰到麻煩。進程1試圖獲取Product表上的一個排他鎖。進程2將在Suppliers表上獲取一個排他鎖。然后進程1將試圖獲取Suppliers表上的一個鎖,但是進程1必須等到進程2清除了現(xiàn)有的鎖。同時進程2也在等待進程1清除現(xiàn)有鎖。

上面的例子是,兩個進程用相反的順序,鎖住兩個表,這樣就很容易發(fā)生死鎖。

如果我們將進程2改成首先在Products減少庫存數(shù)量,接著在Suppliers表中更新銷售產品的總數(shù)量。兩個進程以相同的順序訪問兩張表,這樣就能夠減少死鎖的發(fā)生。

2、使事務盡可能簡短

保持事務的簡短將不會讓你付出任何的代價。在事務中放入想要的內容,把不需要的內容拿出來,就這么簡單。它的原理并不復雜-事務打開的時間越長,它觸及的內容就越多,那么其他一些進程想要得到正在使用的一個或者多個對象的可能性就越大。如果要保持事務簡短,那么就將最小化可能引起死鎖的對象的數(shù)量,還將減少鎖定對象的時間。原理就如此簡單。

3、盡可能使用最低的事務隔離級別

使用較低的隔離級別和較高的隔離級別相比,共享鎖持續(xù)的時間更短,因此會減少鎖的競爭。

4、不要采用允許無限中斷的事務

當開始執(zhí)行某種開放式進程時間,不要創(chuàng)建將一直占有資源的鎖。通常,指的是用戶交互,但它也可能是允許無限等待的任何進程。

到此這篇關于SQL Server鎖的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論