環(huán)境: SQL Server 2005 or 2008
最近在處理一個鎖的問題時,發(fā)現(xiàn)一個比較郁悶的事,使用 X 鎖居然無法鎖住查詢,模擬這個問題,可以使用如下 T-SQL 腳本來建立測試環(huán)境。
USE master ;
GO
IF @@TRANCOUNT > 0
ROLLBACK TRAN ;
GO
-- =======================================
-- 建立測試數(shù)據(jù)庫
-- a. 刪除測試庫 , 如果已經(jīng)存在的話
IF DB_ID ( N'db_xlock_test' ) IS NOT NULL
BEGIN ;
ALTER DATABASE db_xlock_test
SET SINGLE_USER
WITH
ROLLBACK AFTER 0 ;
DROP DATABASE db_xlock_test ;
END ;
-- b. 建立測試數(shù)據(jù)庫
CREATE DATABASE db_xlock_test ;
-- c. 關(guān)閉 READ_COMMITTED_SNAPSHOT 以保持 SELECT 的默認(rèn)加鎖模式
ALTER DATABASE db_xlock_test
SET READ_COMMITTED_SNAPSHOT OFF ;
GO
-- =======================================
-- 建立測試表
USE db_xlock_test ;
GO
CREATE TABLE dbo . tb (
id int IDENTITY
PRIMARY KEY ,
name sysname
);
INSERT dbo . tb
SELECT TOP ( 50000 )
O1 . name + N'.' + O2 . name + N'.' + O3 . name
FROM sys . objects O1 WITH ( NOLOCK ),
sys . objects O2 WITH ( NOLOCK ),
sys . objects O3 WITH ( NOLOCK );
GO
然后,建立一個連接,執(zhí)行下面的腳本來實現(xiàn)加鎖。
-- =======================================
-- 測試連接 1 - 加鎖
BEGIN TRAN
-- 測試的初衷是通過 SELECT 加鎖,結(jié)果發(fā)現(xiàn) UPDATE 也鎖不住
UPDATE dbo . tb SET name = name
--SELECT COUNT(*) FROM dbo.tb WITH(XLOCK)
WHERE id <= 2 ;
SELECT
spid = @@SPID ,
tran_count = @@TRANCOUNT ,
database_name = DB_NAME (),
object_id = OBJECT_ID ( N'dbo.tb' , N'Table' );
-- 顯示鎖
EXEC sp_lock @@SPID ;
通過執(zhí)行結(jié)果,可以看到對象被加鎖的情況:表級和頁級上是 IX 鎖,記錄上是 X 鎖。
spid |
tran_count |
database_name |
object_id |
|
||||||
51 |
1 |
db_xlock_test |
21575115 |
|
||||||
spid |
dbid |
ObjId |
IndId |
Type |
Resource |
Mode |
Status |
|||
51 |
7 |
0 |
0 |
DB |
|
S |
GRANT |
|||
51 |
7 |
21575115 |
1 |
PAG |
0.095138889 |
IX |
GRANT |
|||
51 |
7 |
21575115 |
0 |
TAB |
|
IX |
GRANT |
|||
51 |
1 |
1131151075 |
0 |
TAB |
|
IS |
GRANT |
|||
51 |
7 |
21575115 |
1 |
KEY |
(020068e8b274) |
X |
GRANT |
|||
51 |
7 |
21575115 |
1 |
KEY |
-10086470766 |
X |
GRANT |
|||
然后新建一個連接,執(zhí)行下面的 T-SQL 查詢,看看會否被連接 1 鎖住
-- =======================================
-- 測試連接 2 - 被阻塞 ( 在測試連接 1 執(zhí)行后執(zhí)行 )
SET TRANSACTION ISOLATION LEVEL READ COMMITTED ;
SELECT * FROM dbo . tb
WHERE id <= 2 ;
上述查詢會很快返回結(jié)果,并不會被查詢 1 阻塞住。
按照我們的了解(聯(lián)機(jī)幫助上也有說明),在 READ COMMITTED 事務(wù)隔離級別下,查詢使用共享鎖( S ),而根據(jù)鎖的兼容級別, S 鎖是與 X 鎖沖突的,所以正常情況下,連接 2 的查詢需要等待連接 1 執(zhí)行完成。可是測試的結(jié)果去違反了這一原則。
為了了解為什么連接 2 不會被阻塞,對連接 2 做了一個 Trace ,發(fā)現(xiàn)一個更郁悶的問題, Trace 的結(jié)果如下:
EventClass |
TextData |
ObjectID |
Type |
Mode |
Lock:Acquired |
21575115 |
5 - OBJECT |
6 - IS |
|
Lock:Acquired |
1:77 |
0 |
6 - PAGE |
6 - IS |
Lock:Acquired |
[PLANGUIDE] |
0 |
2 - DATABASE |
3 - S |
Lock:Acquired |
21575115 |
5 - OBJECT |
6 - IS |
|
Lock:Acquired |
1:77 |
0 |
6 - PAGE |
6 - IS |
Lock:Acquired |
1:80 |
0 |
6 - PAGE |
6 - IS |
Lock:Acquired |
width
發(fā)表評論
最新評論
|
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論