要么我做错了(可能),要么APPLOCK_MODE
和APPLOCK_TEST
有时会回错。
在一个标签中,我运行此代码:
begin tran
declare @lock int = -1
exec @lock = sp_getapplock @Resource = 'testlock', @Lockmode = 'Exclusive',
@LockOwner = 'Transaction', @LockTimeout=0
if @lock = 0
print 'got lock'
else
print 'failed to get lock'
waitfor delay '00:00:05'
if @lock = 0
exec sp_releaseapplock @Resource = 'testlock', @LockOwner = 'Transaction'
print 'released lock'
commit
在另一个标签中,我运行此代码:
begin tran
print 'APPLOCK_TEST=' + convert(varchar(max),
APPLOCK_TEST(suser_name(), 'testlock', 'Exclusive', 'Transaction'))
print 'APPLOCK_MODE=' +
APPLOCK_MODE(suser_name(), 'testlock', 'Transaction')
declare @lock int
exec @lock = sp_getapplock @Resource = 'testlock', @Lockmode = 'Exclusive',
@LockOwner = 'Transaction', @LockTimeout=0
print 'Result=' + convert(varchar(max), @lock)
if @lock = 0 -- lock is held
begin
print 'releasing lock'
exec sp_releaseapplock @Resource = 'testlock', @LockOwner = 'Transaction'
end
commit
在第一个选项卡中运行代码然后在第一个选项卡完成之前在第二个选项卡中运行代码时,我看到的是:
APPLOCK_TEST=1
APPLOCK_MODE=NoLock
Result=-1
1
的{{1}}和APPLOCK_TEST
的{{1}}的结果值都表明该锁目前尚未使用,我应该能够获得它。这是错误的,因为锁定仍然由另一个选项卡保持,直到完成为止。实际调用NoLock
失败确认了这一点。
让我感到困惑的是,为什么这两个测试函数的回归与我期望的相反。我在这里缺少某些方面吗?
答案 0 :(得分:1)
您应该将public
指定为主体,而不是suser_name()
,因为这也是获取锁定的(默认)主体。指定APPLOCK_TEST
时(public
将返回0(锁定不可授予)。 APPLOCK_MODE
仍将返回NoLock
,因为它返回当前事务所持有的锁定模式 - 并且当前事务未持有锁定。 (documentation无疑对此不清楚,但确实给出了预期行为的示例。)如果这似乎无用,请考虑多个事务可能持有(可共享)这一事实)锁定在不同的模式。
但是,根据@BenThul的评论,在获取锁定状态之前测试锁定状态是不明智的,因为它的时间点信息在您实际尝试获取锁定时可能无效。很难想象APPLOCK_TEST
可以有意义地使用的情况(与sp_getapplock
相反,具有零或非常小的超时)。