如何检查谁持有我想要授予的锁?

时间:2016-07-28 08:15:06

标签: sql sql-server tsql sql-server-2008-r2

考虑以下情况:

  

公司中的某些用户可能会读取和更新客户数据   数据库(来自前端应用程序)。

     

为避免重复更新同一客户,如果用户A开始修改特定客户的数据,则在用户A完成并更新数据库(用户A持有此客户数据的独占锁)之前,任何人都无法修改该客户的数据。

     

如果其他用户尝试修改相同的客户数据,系统将立即返回错误,指示用户A已在修改此客户的数据。

对于此类要求,当用户A开始编辑客户数据时,我想使用sp_getapplock授予名称为唯一客户ID 的独占锁。然后,当另一个用户尝试编辑时,系统将返回无法授予锁定,因为用户A持有它。

以下是我预期的SQL:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRANSACTION

DECLARE @result INT
EXEC @result = sp_getapplock
            @Resource = 'UniqueCustomerID', @LockMode = 'Exclusive', @LockTimeout = 0

IF @result = 0
    --Successful grant the lock, perform the data update action here
ELSE
    --The lock is holding by someone, return the SPID who holds the lock
COMMIT TRANSACTION

如何检索持有锁定的SPID?我知道sys.sysprocessessp_who可以通过 SPID获取块,但在我的情况下,sql语句需要立即返回而不会阻塞,并获取谁持有锁定它试图授予。有可能,怎么做? 我感谢任何建议和建议: - )

1 个答案:

答案 0 :(得分:3)

要获取持有应用程序锁定的会话ID,您可以查询sys.dm_tran_locks

SELECT request_session_id
FROM   sys.dm_tran_locks
WHERE  resource_type = 'APPLICATION'
       AND request_mode = 'X'
       AND request_status = 'GRANT'
       AND resource_description LIKE '%:\[UniqueCustomerID\]:%' ESCAPE '\' 

UniqueCustomerID最多32个字符(更多将被截断)。

但这需要VIEW SERVER STATE权限。因此,您可能需要将其包装在使用代码签名的存储过程中,或EXECUTE AS暂时提升权限。

按照Mitch的建议滚动你自己的方案不应该太棘手并避免这个问题。

您可以拥有一个包含每位客户行和user_name列的表格,然后在每次交易开始时调用sp_getapplock尝试更新user_name SET LOCK_TIMEOUT 0; }和(如果失败)那么你可以在read uncommitted中读取该行中包含的user_name。在提交之前,我还要让每个事务将其user_name列设置回NULL。如果user_name的读取返回NULL,那么您将知道重试。

该表需要在CustomerId上建立索引以找到该行而不会碰到其他客户的锁。