4

I have two test transactions in two session respectively. Assuming these two transaction will run simultaneously. What I attempt to do is to let one transaction insert invoice number correctly after the other transaction is done. No duplicate. I did it as below. But if I remove with (tablockx) in session 2, they won't work any more. I checked on line book but no answer. Anybody would help? Serializable won't work since two SELECT want to be exclusive to each other here. Thanks.

In session 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 

In session 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 
4

1 回答 1

1

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

如果你这样做,你可能会以更低的粒度(比表)和模式(比独占)锁定WITH(UPDLOCK, HOLDLOCK)

HOLDLOCK提供可序列化的语义,因此可以锁定索引顶部的范围(如果你有一个 on LocName,InvNumber)。

UPDLOCK确保两个并发事务不能同时持有相同的锁,但与独占不同的是,它不会阻塞未使用提示的其他(正常)读取器。

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序列化对该代码的访问。

于 2013-08-28T07:53:38.000 回答