【发布时间】:2013-12-06 01:54:20
【问题描述】:
我需要在我的应用程序中实现一个锁定方案。如果对话框/表单没有被锁定,用户只能打开它。另一方面,如果当前没有打开对应于该锁的对话框,则只能设置锁。
到目前为止我的方法: 我有一个带有列 lockname 的 sql server 表 tbl_lock,我在其中维护锁和一个表 tbl_dialog (user, dialogname),每当用户打开对话框时,我都会在其中创建一行。
要创建一个锁,我执行以下操作: 1) 开始交易 2) select * from tbl_dialog with (SERIALIZABLE) where dialogname=@somename 3) 如果 prio select 没有返回记录,则在 tbl_lock 中为对话框 @somename 插入一个锁定记录 4) 提交事务
问题在于,我还想防止有人在其他用户尝试设置锁定时尝试打开对话框。我可以重复上述 4 个步骤并选择 tbl_lock with serializable 并在 tbl_dialog 中插入一条记录,但我担心如果 2 个并发事务执行步骤会同时锁定两个表 tbl_dialog 和 tbl_lock,我会遇到死锁。
我可以在第 2 步中同时锁定两个表吗?有没有更聪明的方法来解决这个问题?
最好的问候, 萨沙
编辑: 根据 Bogdan 的评论,我将实施以下 SP 来设置锁定:
Create procedure CreateLock
@dialogname nvarchar(10),
@lockname nvarchar(10)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @result int;
DECLARE @locksuccess int = 0;
begin tran;
EXEC @result = sp_getapplock @Resource = 'myapplockmanagement', @LockMode = 'Exclusive', @LockTimeout=3000;
if @result>=0
BEGIN
-- Ensure no user has opened the dialog @lockname
if not EXISTS(select 1 from tbl_dialog where dialogname=@dialogname)
BEGIN
if not EXISTS(select 1 from tbl_lock where lockname=@lockname)
BEGIN
insert into tbl_lock (lockname) values (@lockname);
set @locksuccess = 1;
END
END
commit;
END
ELSE
BEGIN
rollback;
END
return @locksuccess;
END
如果我正确理解了 sp_getapplock,myapplockmanagement 将被独占锁定,从而锁定所有其他线程。如果可以获取应用程序锁,我可以安全地检查我的 tbl_dialog 并最终在 tbl_lock 中插入一个新行,对吗?
所以下一个程序是:
Create procedure RegisterDialogUsage
@dialogname nvarchar(10),
@lockname nvarchar(10)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @result int;
DECLARE @registersuccess int = 0;
begin tran;
EXEC @result = sp_getapplock @Resource = 'myapplockmanagement', @LockMode = 'Exclusive', @LockTimeout=3000;
if @result>=0
BEGIN
-- Ensure that no lock is set.
if not EXISTS(select 1 from tbl_lock where lockname=@lockname)
BEGIN
insert into tbl_dialog (dialogname) values (@dialogname);
set @registersuccess = 1;
END
commit;
END
ELSE
BEGIN
rollback;
END
return @registersuccess;
END
所以,如果我没记错的话,这两个 SP 完全按照我的喜好行事:
- 锁只能在tbl_lock中设置,如果tbl_dialog中没有注册用户
- 如果 tbl_lock 中没有设置锁,则只能在 tbl_dialog 中注册对话使用
- 感谢 sp_getapplock,不会出现并发问题。
对吗? (相应的用于删除 tbl_lock 和 tbl_dialog 中的条目的 SP 必须实现两个......)
萨沙
【问题讨论】:
-
这个应用程序在哪里运行?在服务器上还是在多个客户端机器上?您打算如何处理废弃的锁,例如当应用程序意外关闭时?
-
对,我不够具体。这些应用程序是一个运行在多个客户端计算机上的 .Net 应用程序,所有客户端计算机都连接到同一个 sql 服务器。废弃的锁没问题,因为我用tbl_lock中的条目保存了sql连接id。因此,我可以通过 sys.dm_exec_sessions 检查连接是否仍然存在,如果是,则不会放弃锁。
-
@Sascha:我会使用一个表:dbo.Lock(DialogName, LockName)。在这种情况下,我将在
(DialogName, LockName)上创建一个唯一/主要约束。因此,对于每个对话框,我不能有两个或多个具有相同LockName的锁。在这种情况下,[1] 这些应用程序锁将防止重复密钥,[2] 您只需要一个程序而不是两个。此外,您需要释放这些锁。
标签: sql-server tsql locking