我在并发方案中面临重复增量字段的问题。

我使用EF作为ORM工具,试图插入一个实体,该实体的字段充当增量INT字段。基本上,此字段称为“ SequenceNumber”,其中每个插入前的新记录将使用MAX读取数据库以获取最后一个SequenceNumber,将+1附加到该序列号并保存更改。

在获取最后一个SequenceNumber与保存之间,这就是并发发生的地方。

我没有对ID使用SequenceNumber,因为它不是唯一的约束,并且可能在某些条件下(例如每月,每年等)重置。

InvoiceNumber       | SequenceNumber | DateCreated
INV00001_08_14      | 1              | 25/08/2014
INV00001_08_14      | 1              | 25/08/2014 <= (concurrency is creating two SeqNo 1)
INV00002_08_14      | 2              | 25/08/2014
INV00003_08_14      | 3              | 26/08/2014
INV00004_08_14      | 4              | 27/08/2014
INV00005_08_14      | 5              | 29/08/2014
INV00001_09_14      | 1              | 01/09/2014 <= (sequence number reset)


发票号基于SequenceNumber格式化。

经过研究后,我得出了这些可能的解决方案,但想了解最佳做法


悲观并发,将表锁定为无法进行任何读取,直到当前事务完成为止(不是这个主意,因为我认为性能会产生很大的影响?)
仅为此目的创建存储过程,并选择并在单个语句上插入,因为这样的并发性最少(如果可能,最好使用基于EF的方法)


=============================

编辑

我想到的另一种解决方案是使InvoiceNumber成为唯一约束,因此在重复条目的情况下,它将引发“唯一约束违规”错误,将其捕获,然后重新尝试获得新的SequenceNumber和InvoiceNumber以重新插入数据库。

最佳答案

使用带有身份密钥的假表/实体。

在插入发票之前,在假表中插入以获得ID。
使用ID而不是FK,而是使用SequenceNumber

对于重置:截断假表。

可预测的问题:序列中可能有孔,具体取决于插入错误。

请注意自sql server 2012起的CREATE SEQUENCE。顺便说一句,如果您认为这个主意很好,也请upvote on datavoice

=====

可以通过约束将sql序列用作默认值:

ALTER TABLE Invoice
ADD CONSTRAINT DefSequence DEFAULT (NEXT VALUE FOR InvoiceSeq)
    FOR SequenceNumber;
GO


通过将SequenceNumber设置为DatabaseGeneratedOption.Computed可能是完美的。

10-06 03:47