SQL Server Insert操做中的鎖

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

準備數據

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

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:spa

begin tran t1

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

    而後查看鎖:3d

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;

    執行結果以下:code

  • 第一個是意向排他鎖。它表示這個數據頁下存在排他鎖(就是第三個排他鎖),咱們發現它的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;

但另外一條卻會產生阻塞:blog

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,因此這裏會對已插入但未提交的數據主鍵加一個共享鎖。

相關文章
相關標籤/搜索