我可以同时锁定2张桌子吗?

时间:2013-11-21 14:29:52

标签: sql-server tsql locking

我需要在我的应用程序中实现一个锁定方案。如果用户尚未锁定,则用户只能打开对话框/表单。另一方面,如果当前没有对话框,则只能设置锁定,该锁定对应于该锁定。

到目前为止我的方法: 我有一个带有列lockname的sql server表tbl_lock,我在那里维护锁和一个表tbl_dialog(user,dialogname),每当用户打开一个对话框时我就会创建一行。

要创建锁,我会执行以下操作: 1)开始交易 2)选择*来自tbl_dialog并使用(SERIALIZABLE)其中dialogname = @ somename 3)如果prio select没有返回记录,则在tbl_lock中插入对话框@somename的锁记录 4)提交交易

问题是,我还想阻止有人试图在其他用户尝试设置锁定时打开对话框。我可以重复上面的4个步骤并选择带有serializable的tbl_lock并在tbl_dialog中插入一条记录,但我担心如果2个并发事务执行步骤,我会遇到死锁,从而同时锁定表tbl_dialog和tbl_lock。

我可以一次锁定第2步中的两个表吗?有没有更聪明的方法来解决这个问题?

最诚挚的问候, 的Sascha

编辑: 根据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中插入一个新行,对吗?

所以下一个Procdure将是:

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完全按照我的意愿行事:

  1. 如果在tbl_dialog中没有注册用户,则只能在tbl_lock中设置锁定
  2. 如果tbl_lock中没有设置锁定,则只能在tbl_dialog中注册对话框用法
  3. 感谢sp_getapplock,不会出现并发问题。
  4. 是吗? (用于删除tbl_lock和tbl_dialog中的条目的相应SP必须实现两个......)

    的Sascha