我有一個People表,有三行數(shù)據(jù):
如果我們沒詳細(xì)了解數(shù)據(jù)庫事務(wù)執(zhí)行加鎖的過程中,會不會有這樣一個疑問:如下的這段 SQL 開啟了事務(wù),并且在事務(wù)中進(jìn)行了更新和查詢操作。
BEGIN TRAN
update People set Name='張三' where id=1;
select * from People where id=1;
commit tran
我們知道sql server數(shù)據(jù)庫的默認(rèn)事務(wù)級別是READ COMMITTED(已提交的讀取),我們再看一下已提交讀事務(wù)隔離級別描述:
允許事務(wù)讀取另一個事務(wù)以前讀?。ㄎ葱薷模┑臄?shù)據(jù),而不必等待第一個事務(wù)完成。 SQL Server數(shù)據(jù)庫引擎將保留 (對所選數(shù)據(jù)) 獲取的寫入鎖,直到事務(wù)結(jié)束,但讀取鎖將在執(zhí)行 SELECT 操作后立即釋放。 這是SQL Server數(shù)據(jù)庫引擎默認(rèn)級別。
那么我們在READ COMMITTED 隔離級別下更新People表數(shù)據(jù)庫,按照這個邏輯在id=1的數(shù)據(jù)行上添加排它鎖(X鎖)
并等到事務(wù)提交后才會釋放鎖。
但是事務(wù)繼續(xù)執(zhí)行查詢,在READ COMMITTED隔離級別下 Select 會對查詢數(shù)據(jù)施加共享鎖(S鎖)
。因?yàn)橛信潘i,所以查詢無法獲得共享鎖需要等待排它鎖釋放,如果按照這個邏輯的話這個事務(wù)自身就死鎖無法執(zhí)行了。
但這個事務(wù)還是會正常執(zhí)行完成,針對這個疑問,那么我們看下數(shù)據(jù)庫的事務(wù)和鎖:
數(shù)據(jù)庫引擎隔離級別
ISO 標(biāo)準(zhǔn)定義了以下隔離級別,SQL Server數(shù)據(jù)庫引擎支持所有這些隔離級別:
隔離級別 | 定義 |
---|---|
未提交的讀取 | 隔離事務(wù)的最低級別,只能保證不讀取物理上損壞的數(shù)據(jù)。 在此級別上,允許臟讀,因此一個事務(wù)可能看見其他事務(wù)所做的尚未提交的更改。 |
已提交的讀取 | 允許事務(wù)讀取另一個事務(wù)以前讀?。ㄎ葱薷模┑臄?shù)據(jù),而不必等待第一個事務(wù)完成。 SQL Server數(shù)據(jù)庫引擎將保留 (對所選數(shù)據(jù)) 獲取的寫入鎖,直到事務(wù)結(jié)束,但讀取鎖將在執(zhí)行 SELECT 操作后立即釋放。 這是SQL Server數(shù)據(jù)庫引擎默認(rèn)級別。 |
可重復(fù)的讀取 | SQL Server數(shù)據(jù)庫引擎會保留對所選數(shù)據(jù)獲取的讀取和寫入鎖定,直到事務(wù)結(jié)束。 但是,因?yàn)椴还芾矸秶i,可能發(fā)生虛擬讀取。 |
可序列化 | 隔離事務(wù)的最高級別,事務(wù)之間完全隔離。 SQL Server數(shù)據(jù)庫引擎保留對所選數(shù)據(jù)獲取的讀取和寫入鎖定,這些鎖將在事務(wù)結(jié)束時釋放。 SELECT 操作使用分范圍的 WHERE 子句時獲取范圍鎖,主要為了避免虛擬讀取。 注意: 請求可序列化隔離級別時,復(fù)制的表上的 DDL 操作和事務(wù)可能失敗。 這是因?yàn)閺?fù)制查詢使用的提示可能與可序列化隔離級別不兼容。 |
SQL Server數(shù)據(jù)庫引擎使用不同的鎖模式鎖定資源,這些模式確定并發(fā)事務(wù)如何訪問資源。
T-SQL 設(shè)置事務(wù)隔離級別,只對當(dāng)前會話連接一直有效
SET TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SNAPSHOT
| SERIALIZABLE
}
鎖模式
下表顯示了SQL Server數(shù)據(jù)庫引擎使用的資源鎖模式。
鎖模式 | 說明 |
---|---|
共享 (S) | 用于不更改或不更新數(shù)據(jù)的讀取操作,如 SELECT 語句。 |
更新 (U) | 用于可更新的資源中。 防止當(dāng)多個會話在讀取、鎖定以及隨后可能進(jìn)行的資源更新時發(fā)生常見形式的死鎖。 |
排他 (X) | 用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。 確保不會同時對同一資源進(jìn)行多重更新。 |
意向 | 用于建立鎖的層次結(jié)構(gòu)。 意向鎖包含三種類型:意向共享 (IS)、意向排他 (IX) 和意向排他共享 (SIX)。 |
架構(gòu) | 在執(zhí)行依賴于表架構(gòu)的操作時使用。 架構(gòu)鎖包含兩種類型:架構(gòu)修改 (Sch-M) 和架構(gòu)穩(wěn)定性 (Sch-S)。 |
大容量更新 (BU) | 在將數(shù)據(jù)大容量復(fù)制到表中且指定了 TABLOCK 提示時使用。 |
鍵范圍 | 當(dāng)使用可序列化事務(wù)隔離級別時保護(hù)查詢讀取的行的范圍。 確保再次運(yùn)行查詢時其他事務(wù)無法插入符合可序列化事務(wù)的查詢的行。 |
鎖兼容性
鎖兼容性控制多個事務(wù)能否同時獲取同一資源上的鎖。 如果資源已被另一事務(wù)鎖定,則僅當(dāng)請求鎖的模式與現(xiàn)有鎖的模式相兼容時,才會授予新的鎖請求。 如果請求鎖的模式與現(xiàn)有鎖的模式不兼容,則請求新鎖的事務(wù)將等待釋放現(xiàn)有鎖或等待鎖超時間隔過期。 例如,沒有與排他鎖兼容的鎖模式。 如果具有排他鎖(X 鎖),則在釋放排他鎖(X 鎖)之前,其他事務(wù)均無法獲取該資源的任何類型(共享、更新或排他)的鎖。 另一種情況是,如果共享鎖(S 鎖)已應(yīng)用到資源,則即使第一個事務(wù)尚未完成,其他事務(wù)也可以獲取該項(xiàng)的共享鎖或更新鎖(U 鎖)。 但是,在釋放共享鎖之前,其他事務(wù)無法獲取排他鎖。
下表顯示了最常見的鎖模式的兼容性。
查看執(zhí)行時鎖的情況
通過鎖的兼容性模式我們知道在id=1的行上添加了排它鎖,那么它就無法再接收任何鎖,那我們調(diào)試這個事務(wù)看看鎖的情況。
我們調(diào)試到第3行,這個時候看下鎖的情況,此時事務(wù)添加了key(行)排它鎖X鎖
,page(頁)和object(表)添加了意向排它鎖IX鎖
。
SELECT
resource_type,
resource_database_id,
resource_description,
request_mode,
request_type,
request_session_id,
request_owner_type,
request_owner_id,
lock_owner_address
FROM sys.dm_tran_locks where request_owner_type='transaction'
然后我們再繼續(xù)調(diào)試到第4行,此時還沒提交事務(wù),排它鎖X依然存在,但是沒有S鎖。
我們知道在讀提交事務(wù)隔離級別下,S鎖是使用完了就釋放的,所以我們用SQL Server Profiler來監(jiān)視下鎖的情況,設(shè)置監(jiān)控的項(xiàng)為lock,然后設(shè)置篩選條件。
上面我已經(jīng)將 張三1 改為了 張三,我們再將 張三 改回 張三1,并啟動監(jiān)控。
BEGIN TRAN
update People set Name='張三1' where id=1;
select * from People where id=1;
commit tran
可以看到事務(wù) transactionid=30010685 的鎖監(jiān)控 :
- 首先申請IX更新意向鎖(object,page) 準(zhǔn)備更新,然后獲得行上的X排它鎖進(jìn)行更新,更新后釋放了行鎖和page鎖(EventClass= Lock:released,Mode=0-null)。
- 等查詢時申請page頁IS意向讀取鎖,并獲得行S鎖讀取數(shù)據(jù)后釋放行鎖和page頁鎖。
- 最后還有幾個順序釋放,依次是key、page、Object,這里恰好和上面調(diào)試還沒提交事務(wù)時查詢sys.dm_tran_locks的鎖情況一樣,也就是說事務(wù)提交后依次又進(jìn)行了一遍釋放。
通過上面我們得出結(jié)論,事務(wù)里面并不是取得了X鎖要等事務(wù)結(jié)束后才釋放,在事務(wù)執(zhí)行過程中也是有釋放的,只是事務(wù)還保持著對于鎖在事務(wù)層面的記錄,防止其它事務(wù)并發(fā)(這里是我推斷的,沒找到相關(guān)文獻(xiàn)說明)。
所以事務(wù)是在鎖上更宏觀的邏輯隔離,事務(wù)隔離級別只是在業(yè)務(wù)上保證數(shù)據(jù)符合隔離級別預(yù)期,至于事務(wù)中如何控制鎖是基于數(shù)據(jù)庫內(nèi)在設(shè)計,而不能通過事務(wù)的描述去推斷鎖過程。
我查閱網(wǎng)上很多博文和官方資料都是講事務(wù)和鎖概念,有時候結(jié)合兩種也是模棱兩可看不出什么強(qiáng)聯(lián)系,沒有講事務(wù)執(zhí)行過程中鎖是如何變化的,不知道我這篇推論是否正確,歡迎指正。
再次驗(yàn)證
我將事務(wù)隔離級別設(shè)置為REPEATABLE READ(可重復(fù)讀),然后調(diào)試到commit行還沒提交,我們看跟蹤的鎖和事務(wù)鎖表dm_tran_locks查詢的結(jié)果,按照REPEATABLE READ描述,select查詢的S鎖會在事務(wù)提交后釋放,我們看看截圖情況
開啟了SQL Server Profiler結(jié)果,查詢id=3后S鎖已經(jīng)釋放。
再查dm_tran_locks表,表中依然顯示事務(wù)獲取了S鎖,并且 resource_description=98ec012aa510 資源描述和上面跟蹤是對應(yīng)的。
最后我們執(zhí)行完調(diào)試,跟蹤鎖顯示又按照順序釋放了一遍鎖文章來源:http://www.zghlxwxcb.cn/news/detail-427938.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-427938.html
到了這里,關(guān)于Sql Server 數(shù)據(jù)庫事務(wù)與鎖,同一事務(wù)更新又查詢鎖的變化,期望大家來解惑!的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!