SQL Server 2014:线程安全生成序列号

时间:2019-03-18 11:35:40

标签: sql-server

我需要生成发票的渐进编号,避免序列中出现空白:
一开始我以为这很容易

    SELECT MAX(Docnumber)+1 as NewDocNumber
    from InvoicesHeader

但是由于构建“插入InvoiceHeader”查询需要花费一些时间,并且另一个请求可能到达,因此为两个发票分配了相同的NewDocNumber

我现在正在考虑避免在高级查询和更改后的查询中生成DocNumber:

INSERT INTO InvoicesHeader  (InvoiceID,..., DocNumber,...) 
SELECT @InvoiceID,..., MAX(Docnumber)+1,... FROM InvoicesHeader

但是,尽管(它应该)解决了一些问题,但是它仍然是线程不安全的,并且不适合竞争条件:

以这种方式添加TABLOCKUPDLOCK

BEGIN TRANSACTION  TR1
    INSERT INTO InvoicesHeader WITH (TABLOCK)  
        (InvoiceID,..., DocNumber,...) 
    SELECT @InvoiceID,..., MAX(Docnumber)+1,... FROM InvoicesHeader
COMMIT TRANSACTION  TR1

会解决这个问题吗?

或者更好地使用ISOLATION LEVELNEXT VALUE FOR或其他解决方案?

1 个答案:

答案 0 :(得分:0)

您已经在SQL Server中具有线程安全的序列生成生成。了解有关Create Sequence的信息。从SQL Server 2012开始可用。最好在事务范围之外生成序列。

  

序列号在当前范围之外生成   交易。无论交易是否使用   序列号已提交或回滚。

您可以从序列中获取下一个值。我们一直在使用序列来生成订单号,但是当并行生成多个订单数字时,我们还没有发现问题。

SELECT NEXT VALUE FOR DocumentSequenceNumber; 

已更新,根据注释,如果您有四种不同的文档类型,建议您先生成序列,然后再与特定的文档类型连接。您会更容易理解。在年底,您可以使用ALTER SEQUENCE

重新启动序列
  

RESTART [WITH]将由返回的下一个值   序列对象。如果提供,则RESTART WITH值必须为   小于或等于最大值且大于或等于的整数   等于序列对象的最小值。如果WITH值   省略,序列号将根据原始编号重新开始   创建序列选项。