在SQL Server中的存储过程开始时获取更新表锁定

Jim*_*rne 2 locking sql-server-2005

我正在编写一个SQL Server存储过程,我想在执行存储过程的主体之前锁定表以进行更新.我不想阻止其他进程读取表,但我确实希望阻止其他进程更新表.

这是我的第一次尝试:

CREATE PROCEDURE someProcedure
BEGIN
   SET TRANSACTION ISOLATION LEVEL READ COMITTED
   BEGIN TRANSANCTION
     SELECT COUNT(*) FROM TheTable WITH (UPDLOCK, TABLOCK)

     -- Pause procedure so that we can view the locks with sp_lock
     WAITFOR DELAY '00:15'

     -- Do stuff
   COMMIT
END
Run Code Online (Sandbox Code Playgroud)

当我执行存储过程并调用sp_lock时,我看到表确实已被锁定.但是,它使用Exclusive锁而不是更新锁锁定:

spid | dbid | ObjId     | IndId | Type | Resource | Mode | Status
------------------------------------------------------------------
63   | 10   | 233208031 | 0     | TAB  |          | X    | GRANT
Run Code Online (Sandbox Code Playgroud)

我怎样才能获得更新(U)锁?

gbn*_*gbn 5

你说:

我不想阻止其他进程读取表,但我确实希望阻止其他进程更新表.

在TXN的持续时间内,您只需要一个共享读锁定.这意味着没有其他进程可以与TABLOCK一起获得"写"锁.而且你也不需要COUNT.

...
   BEGIN TRANSANCTION
     SELECT TOP 1 KeyCol FROM TheTable WITH (TABLOCK, HOLDLOCK)
...
Run Code Online (Sandbox Code Playgroud)

为什么你认为你想要一个更新锁定?

HOLDLOCK或SERIALIZABLE

相当于SERIALIZABLE.有关更多信息,请参阅本主题后面的SERIALIZABLE.HOLDLOCK仅适用于指定它的表或视图,并且仅适用于由其使用的语句定义的事务的持续时间....通过保持共享锁限制直到事务完成,而不是无论事务是否已完成,一旦不再需要所需的表或数据页,就立即释放共享锁.

评论后编辑:

  • "排他锁"是指"只使用数据的一个过程".
  • "SERIALIZABLE"基本上意味着持有锁(共享,独家,等等)更长时间.

您不能指定"独占锁定" 允许其他进程读取.这些概念是相互排斥的.您希望防止写入整个表,持久共享/读取锁将执行此操作.这就是SERIALIZABLE的用武之地.

"锁定模式"

共享锁

...当资源上存在共享(S)锁时,没有其他事务可以修改数据.一旦读取操作完成,就释放资源上的共享(S)锁,除非事务隔离级别设置为可重复读取或更高,或者使用锁定提示在持续时间内保留共享(S)锁定.交易.

所以:共享锁不允许写入,并且可以通过使其成为SERIALIZABLE来保持写入