我的业务要求是InvoiceNumber
表中的Invoices
字段完全是连续的 - 没有间隙或审计员可能会认为我们的会计师有些可疑!
我的第一个想法是简单地使用主键(标识),但如果事务被回滚,则序列中会出现间隙。
所以我的第二个想法是使用一个触发器,在插入点,它会在表中查找最高InvoiceNumber
值,向其中添加1,并将其用作InvoiceNumber
新行。易于实施。
近同步插入是否存在潜在问题?例如,同时运行触发器的两个几乎同时插入可能获得相同的“当前最高InvoiceNumber
”值,因此插入具有相同InvoiceNumber
的行?
我可能还有其他问题吗?另一种方法会更好吗?
答案 0 :(得分:0)
创建一个保存“计数器”轨迹的表格。 对于您的发票,您可以向该表添加一些记录,以跟踪必须使用的下一个整数 创建发票时,您应该使用该值并增加它。当您的事务回滚时,该计数器的更新也将被回滚。 (确保您锁定该表,以确保没有其他进程可以使用相同的值。)
这比查看发票表中使用的最高当前计数器要可靠得多。
答案 1 :(得分:0)
CREATE TABLE dbo.Sequence(
val int
)
插入包含初始种子的行。然后为插入分配一个足够大小的范围(显然在同一个事务中调用它)
CREATE PROC dbo.GetSequence
@val AS int OUTPUT,
@n as int =1
AS
UPDATE dbo.Sequence
SET @val = val = val + @n;
SET @val = @val - @n + 1;
这将阻止其他并发尝试增加序列,直到第一个事务提交。
答案 2 :(得分:0)
如果从表中删除数据,您可能仍会遇到空白。但是如果数据只进入而不进入,那么通过在外部序列表上正确使用事务,应该可以很好地完成这项工作。不要使用MAX()+ 1因为它可能有时间问题,或者你可能需要锁定更多的表(页面/表格)而不是所需的。
拥有一个只有一个记录和列的顺序表。以原子方式从表中检索数字,将检索和使用包装在单个事务中。
begin tran
declare @next int
update seqn_for_invoice set @next=next=next+1
insert invoice (invoicenumber,...) value (@next, ....)
commit
UPDATE语句是原子的,不能被中断,双重赋值使@next的值成为原子。它相当于使用SQL Server 2005+中的OUTPUT子句来返回更新的值。如果您需要一次性使用一系列数字,则更容易使用PRE更新值而不是POST更新值,即
begin tran
declare @next int
update seqn_for_invoice set @next=next, next=next+3 -- 3 in one go
insert invoice (invoicenumber,...) value (@next, ....)
insert invoice (invoicenumber,...) value (@next+1, ....)
insert invoice (invoicenumber,...) value (@next+2, ....)
commit
的参考
SET @variable = column = expression将变量设置为与列相同的值。这与SET @variable = column,column = expression不同,后者将变量设置为列的更新前值。