是否必须在每个会话中指定tablockx?

时间:2013-08-27 23:09:00

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

我分别在两个会话中有两个测试事务。假设这两个事务将同时运行。我尝试做的是让一个事务在另一个事务完成后正确插入发票号。没有重复。我做了如下。但是如果我在会话2中使用(tablockx)删除它们将不再工作。我查了线书,但没有回答。有人会帮忙吗? Serializable将无法工作,因为这两个SELECT希望彼此独占。感谢。

在第1节:

begin transaction 
    declare @i int
    select @i=MAX(InvNumber) from Invoice 
    with(tablockx) 
    where LocName='A'
    waitfor delay '00:00:10'
    set @i=@i+1
    insert into Invoice values('A',@i);
commit 

在第2节:

begin transaction 
    declare @i int
    select @i=MAX(InvNumber) from Invoice 
    with(tablockx) 
    where LocName='A'
    set @i=@i+1
    insert into Invoice values('A',@i);
commit 

1 个答案:

答案 0 :(得分:1)

这将有效,但也会完全阻止对该表的所有其他访问。

如果执行WITH(UPDLOCK, HOLDLOCK),您可能会以较低的粒度(比表格)和模式(而不是独占)锁定。

HOLDLOCK给出了可序列化的语义,因此只需锁定索引顶部的范围(如果LocName,InvNumber上有一个)。

UPDLOCK确保两个并发事务不能同时拥有相同的锁,但与exclusive不同,不会阻止未使用提示的其他(普通)读者。

BEGIN TRANSACTION

DECLARE @i INT

SELECT @i = MAX(InvNumber)
FROM   Invoice WITH(UPDLOCK, HOLDLOCK)
WHERE  LocName = 'A'

WAITFOR delay '00:00:10'

SET @i=@i + 1

INSERT INTO Invoice
VALUES     ('A',
            @i);

COMMIT 

或者,您可以使用sp_getapplock来序列化对该代码的访问。