關於X鎖的問題--由select+X鎖是否持有到事務結束的誤區


前言:看了宋桑的文章《一次意外的X鎖不阻塞問題》,結合本人的測試,說明一下我對select中使用X鎖是否會持有到事務結束產生的誤區;

詳情不多說了,詳見宋桑的《一次意外的X鎖不阻塞問題》和《消失的共享鎖》,對Select+X鎖和Select+S鎖的情況進行了解釋。以下只描述我的測試;測試表結構及數據如下:

 1 /****** Script for SelectTopNRows command from SSMS  ******/
 2 CREATE TABLE [test_a].[dbo].[tmp_byxl_01](id INT IDENTITY,flag int)
 3 INSERT INTO [test_a].[dbo].[tmp_byxl_01](flag) VALUES(null)
 4 go 7
 5 UPDATE [test_a].[dbo].[tmp_byxl_01] SET flag=id 
 6 
 7 SELECT TOP 1000 [id]
 8       ,[flag]
 9   FROM [test_a].[dbo].[tmp_byxl_01]
10 
11 
12 -------------------------------
13 id          flag
14 ----------- ----
15 1           1
16 2           2
17 3           3
18 4           4
19 5           5
20 6           6
21 7           7
22 
23 (7 行受影響)

 

由於案例出自系統續費問題,業務采用的是調用存儲過程的方式實現,因此每一次調用時,都是select+X鎖的方式;這和上述文章中提到的“Select+X鎖和Select+S鎖”的情況不太相同

先說我的誤區

誤區:select中指定的X鎖將在查詢結束后立即釋放,並不持續到tran結束

測試代碼如下:

--Session_A
BEGIN TRANSELECT * FROM [test_a].[dbo].[tmp_byxl_01](xlock) WHERE flag=2
  WAITFOR DELAY '00:00:10'
COMMIT--Session_B
BEGIN TRANSELECT * FROM [test_a].[dbo].[tmp_byxl_01](xlock) WHERE flag=2
COMMIT

由於兩個tran都是申請xlock,在執行時,Session_A(spid=53)先執行,Session_B(spid=55)大約5秒后執行,通過SP_LOCK可以看到,spid=55申請X鎖時被阻塞

從執行時間上看,spid(55)晚於spid(53)5秒左右開始,執行時間上基本吻合。

這個測試驗證了上述的誤區。加在Select上的X鎖持續到了tran結尾,因此才能阻塞其他進程的相同查詢(也是Xlock)如此長的時間;

 

對於此類情況,一般應用的場景如商家的充值系統、搶購系統等

需要將大並發的環境轉化為單一進程持有鎖的情況(select是為了進行判斷,如賬戶起始金額不能為負、或查詢當前商品信息以防出現超售的情況)

對於此類問題,個人認為,增加Xlock進行查詢,是為了有效的避免臟讀,盡管增加pagelock的方式可以避免S鎖的優化問題,但可能導致鎖范圍過大。

如果不存在普通S鎖的查詢,不添加pagelock提升鎖級別,也是可以滿足大並發需求的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM