考虑以下情况:
公司中的某些用户可能会读取和更新客户数据 数据库(来自前端应用程序)。
为避免重复更新同一客户,如果用户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.sysprocesses
和sp_who
可以通过 SPID获取块,但在我的情况下,sql语句需要立即返回而不会阻塞,并获取谁持有锁定它试图授予。有可能,怎么做?
我感谢任何建议和建议: - )
答案 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
上建立索引以找到该行而不会碰到其他客户的锁。