SQL 并发环境下的数字生成(事务隔离级别)

SQL number generation in concurrent environment (Transation isolation level)

我正在使用一个生成发票编号的应用程序(按顺序基于几个参数),到目前为止它一直在使用带有序列化事务的触发器。因为触发器相当 "heavy" 它设法使插入查询的执行超时。

我现在正在研究该问题的解决方案,到目前为止,我已经到了这样的地步,我有一个执行插入的存储过程,在插入之后我有一个隔离级别可序列化的事务(由方式仅适用于该交易还是我应该在交易提交后将其设置回去?)那:

我想知道是否有更好的方法来确保数字被使用一次并在 table 锁定的情况下获得增量(只有数字 tables 被锁定,对吗?)。

我读到了 sp_getapplock,这是实现我目标的更好方法吗?

如果您先插入然后更新,您有一段时间 window 设置了无效数字并且可以观察到。此外,如果第二笔交易失败(这种情况总是会发生),您的数据就会不一致。

试试这个:

  1. 在 tran 1 中取一个新号码。
  2. 在 tran 2 中插入已经使用的号码

这样你可能会烧掉一个数字,但永远不会有不一致的数据。

我会优化更新例程(并单独处理“insert if not there”),此时它将是:

declare @number int;

update tbl
set @number = number, number += 1
where year = @year and month = @month and office = @office and type = @type;

您不需要任何特定的锁定提示或隔离级别,SQL服务器将确保在递增之前没有两个事务读取相同的值。


如果您想避免单独处理插入,您可以:

merge into tbl
using (values (@year, @month, @office, @type)) as v(y,m,o,t)
on tbl.year = v.year and tbl.month = v.month and tbl.office = v.office and tbl.type = v.type
when not matched by target then
  insert (year, month, office, type, number) values(@year, @month, @office, @type, 1)
when matched then
  update set @number = tbl.number, tbl.number += 1
;

从逻辑上讲,这应该提供与 update 相同的竞争条件防护,但出于某种原因,我不记得证据在哪里。