數(shù)據(jù)庫鎖機制
這段時間由于開發(fā)項目,重新學習了數(shù)據(jù)庫的并發(fā)控制和鎖機制。數(shù)據(jù)庫就是通過鎖機制來解決并發(fā)問題的。。主要就是兩種鎖,共享鎖和排他鎖(也叫獨占鎖)。在執(zhí)行select語句的時候需要給操作對象(表或者一些記錄)加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖(一個對象上可以加n個共享鎖),否則不行。共享鎖通常在執(zhí)行完select語句之后被釋放,當然也有可能是在事務(wù)結(jié)束(包括正常結(jié)束和異常結(jié)束)的時候被釋放,主要取決與數(shù)據(jù)庫所設(shè)置的事務(wù)隔離級別。
執(zhí)行insert、update、delete語句的時候需要給操作的對象加排他鎖(我感覺在執(zhí)行insert的時候應(yīng)該是在表級加排他鎖),在加排他鎖之前必須確認該對象上沒有其他任何鎖,一旦加上排他鎖之后,就不能再給這個對象加其他任何鎖。排他鎖的釋放通常是在事務(wù)結(jié)束的時候(當然也有例外,就是在數(shù)據(jù)庫事務(wù)隔離級別被設(shè)置成Read
Uncommitted(讀未提交數(shù)據(jù))的時候,這種情況下排他鎖會在執(zhí)行完更新操作之后就釋放,而不是在事務(wù)結(jié)束的時候)。
數(shù)據(jù)庫是支持在一個事務(wù)中進行自動鎖升級的,例如,在某個事務(wù)中先執(zhí)行select語句,后執(zhí)行update語句,這兩條語句操作了同一個對象,并且假定共享鎖是在事務(wù)結(jié)束的時候被釋放的。如果數(shù)據(jù)庫不支持自動鎖升級,那么當update語句請求排他鎖的時候?qū)⒉荒艹晒ΑR驗橹皊elect語句的共享鎖沒有被釋放,那么事務(wù)就進入了無限等待,即死鎖。有了自動鎖升級,在執(zhí)行update語句的時候就可以將之前加的共享鎖升級為排他鎖,但有個前提,就是這個共享鎖必須是本事務(wù)自己加的,而且在操作對象上沒有在加其他任何鎖,否則共享鎖是不能被升級為排他鎖的,必須等待其他鎖的釋放。
在看《精通Hibernate》的時候,里面還提到了更新鎖。因為通常在執(zhí)行更新操作的時候要先查詢,也就是我們通常會在update語句和delete語句中加where子句。那么,有的數(shù)據(jù)庫系統(tǒng)可能會在執(zhí)行查詢的時候先給操作對象加共享鎖,然后在更新的時候加排他鎖,但這么做會有問題,也就是如果兩個事務(wù)同時要更新一個對象,都先給這個對象加了共享鎖,當要更新的時候,都請求升級鎖,但由于這個對象上存在對方事務(wù)加的共享鎖。。所以無法升級。這樣兩個事務(wù)就在等待對方釋放共享鎖,進入死鎖狀態(tài)。更新鎖就是為了解決這個問題,即在執(zhí)行查詢操作的時候加的不是共享鎖而是更新鎖(一個對象上只能有一個更新鎖和n個共享鎖),當要更新的時候,再將更新鎖升級為排他鎖,升級前提是這個對象上只有本事務(wù)加的更新鎖,沒有其他任何鎖了。其實,,我想,如果在執(zhí)行查詢的時候就給事務(wù)加排他鎖不也能解決死鎖問題嗎,但這樣似乎會減弱系統(tǒng)的并發(fā)性能。
現(xiàn)在說說數(shù)據(jù)庫的事務(wù)隔離級別。
在《精通Hibernate》中提到了4種數(shù)據(jù)庫事務(wù)隔離級別:
Read Uncommitted:讀未提交數(shù)據(jù)(這個通常很少用)
使用這種隔離級別并不是說在讀取或者更新數(shù)據(jù)的時候不加鎖。。其實還是加鎖的,只是在執(zhí)行完操作之后馬上釋放鎖。而不是等到事務(wù)結(jié)束之后再釋放。對于共享鎖,排他鎖都是這樣。
Read Committed:讀已提交數(shù)據(jù)(這個很常用,也常是數(shù)據(jù)庫默認的設(shè)置)
這種隔離級別共享鎖在讀取數(shù)據(jù)之后馬上釋放。。而排他鎖則是在事務(wù)結(jié)束的時候再釋放。
Repeatable Read:可重復讀
這種隔離級別共享鎖和排他鎖都是在事務(wù)結(jié)束的時候再釋放的。因此叫“可重復讀”,即一個事務(wù)所讀取的數(shù)據(jù)是不會被別的事務(wù)更新的。。。在事務(wù)執(zhí)行過程中任何時候都可以讀取剛才讀過的數(shù)據(jù)。讀過的數(shù)據(jù)是不會被改變的,直到事務(wù)結(jié)束。
Serializable:串行化
共享鎖和排他鎖也是在事務(wù)結(jié)束的時候被釋放,和Repeatable Read不同的是,通常,Repeatable Read。。在讀取數(shù)據(jù)的時候。。都是對一條條記錄加共享鎖的。而Serializable的共享鎖則是對整個表加的,這樣不但讀取的數(shù)據(jù)不會被別的事務(wù)修改。。。在同一個表中的其他未被讀取的數(shù)據(jù)也不會被修改,,甚至不用擔心讀到新加入這個表中的數(shù)據(jù)(根本無法往表中加數(shù)據(jù)),所以這種隔離級別是不會出現(xiàn)虛讀的。
以下一篇來自點擊打開鏈接
鎖是網(wǎng)絡(luò)數(shù)據(jù)庫中的一個非常重要的概念,它主要用于多用戶環(huán)境下保證數(shù)據(jù)庫完整性和一致性。各種大型數(shù)
據(jù)庫所采用的鎖的基本理論是一致的,但在具體實現(xiàn)上各有差別。目前,大多數(shù)數(shù)據(jù)庫管理系統(tǒng)都或多或少具有自我調(diào)節(jié)、自我管理的功能,因此很多用戶實際上不 清楚鎖的理論和所用數(shù)據(jù)庫中鎖的具體實現(xiàn)。?
Microsoft SQL Server(以下簡稱SQL Server)作為一種中小型數(shù)據(jù)庫管理系統(tǒng),已經(jīng)得到了廣泛的應(yīng)用,該系統(tǒng)更強調(diào)由系統(tǒng)來管理鎖。在用戶有SQL請求時,系統(tǒng)分析請求,自動在滿足鎖定 條件和系統(tǒng)性能之間為數(shù)據(jù)庫加上適當?shù)逆i,同時系統(tǒng)在運行期間常常自動進行優(yōu)化處理,實行動態(tài)加鎖。對于一般的用戶而言,通過系統(tǒng)的自動鎖定管理機制基本
可以滿足使用要求,但如果對數(shù)據(jù)安全、數(shù)據(jù)庫完整性和一致性有特殊要求,就必須自己控制數(shù)據(jù)庫的鎖定和解鎖,這就需要了解SQL Server的鎖機制,掌握數(shù)據(jù)庫鎖定方法。?
鎖的多粒度性以及鎖升級?
數(shù)據(jù)庫中的鎖是指一種軟件機制,用來指示某個用 戶(也即進程會話,下同)已經(jīng)占用了某種資源,從而防止其他用戶做出影響本用戶的數(shù)據(jù)修改或?qū)е聰?shù)據(jù)庫數(shù)據(jù)的非完整性和非一致性。這兒所謂資源,主要指用 戶可以操作的數(shù)據(jù)行、索引以及數(shù)據(jù)表等。根據(jù)資源的不同,鎖有多粒度(multigranular)的概念,也就是指可以鎖定的資源的層次。SQL Server中能夠鎖定的資源粒度包括:數(shù)據(jù)庫、表、區(qū)域、頁面、鍵值(指帶有索引的行數(shù)據(jù))、行標識符(RID,即表中的單行數(shù)據(jù))。?
采 用多粒度鎖的重要用途是用來支持并發(fā)操作和保證數(shù)據(jù)的完整性。SQL Server根據(jù)用戶的請求,做出分析后自動給數(shù)據(jù)庫加上合適的鎖。假設(shè)某用戶只操作一個表中的部分行數(shù)據(jù),系統(tǒng)可能會只添加幾個行鎖(RID)或頁面 鎖,這樣可以盡可能多地支持多用戶的并發(fā)操作。但是,如果用戶事務(wù)中頻繁對某個表中的多條記錄操作,將導致對該表的許多記錄行都加上了行級鎖,數(shù)據(jù)庫系統(tǒng)
中鎖的數(shù)目會急劇增加,這樣就加重了系統(tǒng)負荷,影響系統(tǒng)性能。因此,在數(shù)據(jù)庫系統(tǒng)中,一般都支持鎖升級(lock escalation)。所謂鎖升級是指調(diào)整鎖的粒度,將多個低粒度的鎖替換成少數(shù)的更高粒度的鎖,以此來降低系統(tǒng)負荷。在SQL Server中當一個事務(wù)中的鎖較多,達到鎖升級門限時,系統(tǒng)自動將行級鎖和頁面鎖升級為表級鎖。特別值得注意的是,在SQL Server中,鎖的升級門限以及鎖升級是由系統(tǒng)自動來確定的,不需要用戶設(shè)置。?
鎖的模式和兼容性?
在數(shù)據(jù)庫中加鎖時,除了可以對不同的資源加鎖,還可以使用不同程度的加鎖方式,即鎖有多種模式,SQL Server中鎖模式包括:?
1.共享鎖?
SQL Server中,共享鎖用于所有的只讀數(shù)據(jù)操作。共享鎖是非獨占的,允許多個并發(fā)事務(wù)讀取其鎖定的資源。默認情況下,數(shù)據(jù)被讀取后,SQL Server立即釋放共享鎖。例如,執(zhí)行查詢“SELECT * FROM my_table”時,首先鎖定第一頁,讀取之后,釋放對第一頁的鎖定,然后鎖定第二頁。這樣,就允許在讀操作過程中,修改未被鎖定的第一頁。但是,事務(wù)
隔離級別連接選項設(shè)置和SELECT語句中的鎖定設(shè)置都可以改變SQL Server的這種默認設(shè)置。例如,“ SELECT * FROM my_table HOLDLOCK”就要求在整個查詢過程中,保持對表的鎖定,直到查詢完成才釋放鎖定。?
2.修改鎖?
修 改鎖在修改操作的初始化階段用來鎖定可能要被修改的資源,這樣可以避免使用共享鎖造成的死鎖現(xiàn)象。因為使用共享鎖時,修改數(shù)據(jù)的操作分為兩步,首先獲得一 個共享鎖,讀取數(shù)據(jù),然后將共享鎖升級為獨占鎖,然后再執(zhí)行修改操作。這樣如果同時有兩個或多個事務(wù)同時對一個事務(wù)申請了共享鎖,在修改數(shù)據(jù)的時候,這些 事務(wù)都要將共享鎖升級為獨占鎖。這時,這些事務(wù)都不會釋放共享鎖而是一直等待對方釋放,這樣就造成了死鎖。如果一個數(shù)據(jù)在修改前直接申請修改鎖,在數(shù)據(jù)修
改的時候再升級為獨占鎖,就可以避免死鎖。修改鎖與共享鎖是兼容的,也就是說一個資源用共享鎖鎖定后,允許再用修改鎖鎖定。?
3.獨占鎖?
獨占鎖是為修改數(shù)據(jù)而保留的。它所鎖定的資源,其他事務(wù)不能讀取也不能修改。獨占鎖不能和其他鎖兼容。?
4.結(jié)構(gòu)鎖?
結(jié)構(gòu)鎖分為結(jié)構(gòu)修改鎖(Sch-M)和結(jié)構(gòu)穩(wěn)定鎖(Sch-S)。執(zhí)行表定義語言操作時,SQL Server采用Sch-M鎖,編譯查詢時,SQL Server采用Sch-S鎖。?
5.意向鎖?
意 向鎖說明SQL Server有在資源的低層獲得共享鎖或獨占鎖的意向。例如,表級的共享意向鎖說明事務(wù)意圖將獨占鎖釋放到表中的頁或者行。意向鎖又可以分為共享意向鎖、 獨占意向鎖和共享式獨占意向鎖。共享意向鎖說明事務(wù)意圖在共享意向鎖所鎖定的低層資源上放置共享鎖來讀取數(shù)據(jù)。獨占意向鎖說明事務(wù)意圖在共享意向鎖所鎖定 的低層資源上放置獨占鎖來修改數(shù)據(jù)。共享式獨占鎖說明事務(wù)允許其他事務(wù)使用共享鎖來讀取頂層資源,并意圖在該資源低層上放置獨占鎖。?
6.批量修改鎖?
批量復制數(shù)據(jù)時使用批量修改鎖??梢酝ㄟ^表的TabLock提示或者使用系統(tǒng)存儲過程sp_tableoption的“table lock on bulk load”選項設(shè)定批量修改鎖。?
另外,SQL Server命令語句操作會影響鎖定的方式,語句的組合也同樣能產(chǎn)生不同的鎖定,詳情如下表:?
鎖沖突及其防止辦法?
在數(shù)據(jù)庫系統(tǒng)中,死鎖是指多個用戶(進程)分別鎖定了一個資源,并又試圖請求鎖定對方已經(jīng)鎖定的資源,這就產(chǎn)生了一個鎖定請求環(huán),導致多個用戶(進程)都處于等待對方釋放所鎖定資源的狀態(tài)。?
在SQL Server中,系統(tǒng)能夠自動定期搜索和處理死鎖問題。系統(tǒng)在每次搜索中標識所有等待鎖定請求的進程會話,如果在下一次搜索中該被標識的進程仍處于等待狀態(tài),SQL Server就開始遞歸死鎖搜索。