sta*_*ire 18 sql identity locking increment max
我需要在SQL Server 2008列中增加一个整数.
听起来我应该使用一个IDENTITY列,但我需要为每个客户增加单独的计数器.想想一个电子商务网站,每个客户都会从1开始获取自己的递增订单号.这些值必须是唯一的(每个客户).
例如,
Customer1 (Order #s 1,2,3,4,5...)
Customer2 (Order #s 1,2,3,4,5...)
Run Code Online (Sandbox Code Playgroud)
从本质上讲,我需要手动完成SQL identity函数的工作,因为客户数量是无限的,我需要order #每个客户的计数器.
我很自在地做:
BEGIN TRANSACTION
SELECT @NewOrderNumber = MAX(OrderNumber)+1 From Orders where CustomerID=@ID
INSERT INTO ORDERS VALUES (@NewOrderNumber, other order columns here)
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)
我的问题是锁定和并发问题,并确保一个独特的价值.看来我们需要锁定TABLOCKX.但这是一个高容量的数据库,Orders每次我需要执行一个SELECT MAX+1进程并插入一个新的订单记录时,我不能只锁定整个表.
但是,如果我不锁定整个表格,那么我可能无法为该客户获得唯一的价值.由于我们的一些订单输入是通过多线程Windows进程批量完成的,因此有两个操作可能同时要为同一客户插入新订单.
那么什么锁定方法或技术将避免死锁,仍然让我维持PER客户的唯一递增订单数量?
我将引入一个表来保持每个客户的最后一个数字,以便在订单生成的同一事务中查询和更新它.
TABLE CustomerNextOrderNumber
{
CustomerID id PRIMARY KEY,
NextOrderNumber int
}
Run Code Online (Sandbox Code Playgroud)
选择更新锁定将有助于避免同一客户同时下达两个订单时的竞争条件.
BEGIN TRANSACTION
DECLARE @NextOrderNumber INT
SELECT @NextOrderNumber = NextOrderNumber
FROM CustomerNextOrderNumber (UPDLOCK)
WHERE CustomerID = @CustomerID
UPDATE CustomerNextOrderNumber
SET NextOrderNumber = NextOrderNumber + 1
WHERE CustomerID = @CustomerID
... use number here
COMMIT
Run Code Online (Sandbox Code Playgroud)
类似但更简单的方法(受Joachim Isaksson启发)更新锁定是由第一次更新强加的.
BEGIN TRANSACTION
DECLARE @NextOrderNumber INT
UPDATE CustomerNextOrderNumber
SET NextOrderNumber = NextOrderNumber + 1
WHERE CustomerID = @CustomerID
SELECT @NextOrderNumber = NextOrderNumber
FROM CustomerNextOrderNUmber
where CustomerID = @CustomerID
Run Code Online (Sandbox Code Playgroud)
...
COMMIT
Run Code Online (Sandbox Code Playgroud)
在SQL Server 2005和更高版本中,最好是自动完成,而不使用任何事务或锁定:
update ORDERS
set OrderNumber=OrderNumber+1
output inserted.OrderNumber where CustomerID=@ID
Run Code Online (Sandbox Code Playgroud)