SQL Server Insert操作中的鎖


    這篇博文簡單介紹一下在SQL Server中一條Insert語句中用到的鎖。

准備數據

    首先我們建立一張表Table_1,它有兩列Id(bigint)和Value(varchar),其中Id建立了主鍵。

CREATE TABLE [dbo].[Table_2](
    [Id] [bigint] NOT NULL,
    [Value] [nchar](10) NULL,
 CONSTRAINT [PK_Table_2] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
View Code

 

    然后插入兩條數據。

insert into dbo.table_2
(id, value)
values
(1, '1'),
(2, '2');

 

開始測試

    我們知道,在Transaction中共享鎖在查詢語句結束就釋放了,而排它鎖則在Transaction提交才釋放。我們可以利用它來執行一個Insert,不提交Transaction,然后去查看鎖的狀態。注意,本文中查詢窗口配置的Transaction隔離級別是默認值READ COMMITTED。

    首先執行以下SQL:

begin tran t1

insert into dbo.table_2
(id, value)
values
(3, '3');

    然后查看鎖:

SELECT 
    resource_type,
    request_mode,
    resource_description,
    request_session_id,
    request_status,
    resource_associated_entity_id,
    DB_NAME(resource_database_id)as resource_database
FROM
    sys.dm_tran_locks
WHERE
    resource_type <> 'DATABASE'
ORDER BY
    request_session_id;

    執行結果如下:

  • 第一個是意向排他鎖。它表示這個數據頁下存在排他鎖(就是第三個排他鎖),我們發現它的resource_associated_entity_id和第三個鎖一樣。那么,這個數據頁就是存放這行數據的這個主鍵的。
  • 第二個也是意向排他。它的resource_type是OBJECT,此對象可以是數據表、視圖、存儲過程、擴展存儲過程或任何具有對象 ID 的對象。它的resource_associated_entity_id這一列其實是object_id, 用函數object_name(object_id)看一下發現結果是Table_2。那么它下面存在的排他鎖指的也是第三個鎖了。
  • 第三個是排他鎖。resou_description指的是插入數據主鍵的哈希值。

補充1

    此時,我們在另外一個命令窗口中執行以下查詢語句不會產生阻塞:

SELECT *
FROM dbo.Table_2
WHERE id=1;

但另一條卻會產生阻塞:

SELECT *
FROM dbo.Table_2
WHERE id=3;

來看看第一條SQL產生的鎖。由於共享鎖會在查詢結束立即釋放,因此我們加一個HOLDLOCK,讓它在事務結束再釋放:

begin tran t2

SELECT *
FROM dbo.Table_2 WITH(HOLDLOCK)
WHERE id=1;

 

這是執行完以上語句鎖的情況:

第二條SQL會產生阻塞,因此可以直接查詢然后看鎖的情況:

我們發現第9行的resource_description和第3行是相同的,這也說明了主鍵的鎖只是鎖住了某一個值而已。

補充2

這條SQL也會被Insert阻塞:

SELECT
    value
FROM
    dbo.Table_2
WHERE
    value='1'

而且查看當前的鎖可以發現,Key被鎖的值正是Insert語句的Key值。這里有兩個疑問:1. 為什么沒用到主鍵列,卻產生了主鍵鎖。2.為什么Insert的數據還未commit,這里卻會產生這一行主鍵的鎖。

答:1. 我們查看查詢計划,可以看到這條語句是用了聚集索引掃描,至於為什么不是表掃描,請看這里。 2. 由於事務隔離級別默認是Read Committed,所以這里會對已插入但未提交的數據主鍵加一個共享鎖。


免責聲明!

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



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