在SQL Server中生成订单号的正确方法

Ant*_*lev 7 concurrency locking sql-server-2008

这个问题肯定适用于更广泛的范围,但现在就是这样.

我有一个基本的电子商务应用程序,用户可以自然地下订单.所述订单需要有一个唯一的编号,我现在正试图生成.

每个订单都是特定于供应商的.基本上,我有一张OrderNumberInfo (VendorID, OrderNumber)桌子.现在,无论何时客户下订单,我都需要OrderNumber为特定供应商增加并返回该值.当然,我不希望其他进程干扰我,所以我需要以某种方式独占锁定这一行:

begin tranaction

    declare @n int
    select @n = OrderNumber 
      from OrderNumberInfo 
      where VendorID = @vendorID

    update OrderNumberInfo 
      set OrderNumber = @n + 1 
      where OrderNumber = @n and VendorID = @vendorID

commit transaction
Run Code Online (Sandbox Code Playgroud)

现在,我已经阅读过select ... with (updlock rowlock),悲观锁定等等,但是不能将所有这些都放在一个连贯的图片中:

  • 这些提示如何与SQL Server 2008s的快照隔离一起使用?
  • 它们是否执行行级,页级甚至表级锁?
  • 这如何容忍多个用户尝试为单个供应商生成数字?
  • 这里有什么隔离级别?
  • 一般来说 - 做这些事情的方法是什么?

编辑

只是为了让事情更清楚:

  • 在应用程序的这个特定角落的性能绝对不是问题:订单将相对不频繁地进行,并且将涉及对供应商的Web服务的昂贵调用,因此1秒延迟是相当容忍的
  • 我们确实需要让每个供应商的订单号都是独立且顺序的

Luk*_*keH 3

你可以使用一个OUTPUT子句。这应该以原子方式完成这一切,而不需要事务。

-- either return the order number directly as a single column resultset
UPDATE OrderNumberInfo 
SET OrderNumber = OrderNumber + 1
    OUTPUT DELETED.OrderNumber
WHERE VendorID = @vendorID


-- or use an intermediate table variable to get the order number into @n
DECLARE @n INT
DECLARE @temp TABLE ( OrderNumber INT )

UPDATE OrderNumberInfo 
SET OrderNumber = OrderNumber + 1
    OUTPUT DELETED.OrderNumber
    INTO @temp ( OrderNumber )
WHERE VendorID = @vendorID

SET @n = (SELECT TOP 1 OrderNumber FROM @temp)
Run Code Online (Sandbox Code Playgroud)

上面的示例假设该VendorID列具有唯一约束,或者至少每个供应商 ID 仅有一行。如果情况并非如此,那么您可能会更新和/或返回多行,这似乎不是一个好主意!