我在并发方案中面临重复增量字段的问题。
我使用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
可能是完美的。