我正在使用生成发票编号的应用程序(按顺序基于几个参数),到目前为止,它一直使用带序列化事务的触发器。因为触发器很重而且很重。它设法超时插入查询的执行。
我现在正致力于该问题的解决方案,到目前为止,我已经到了我有一个存储过程执行插入的点,在插入之后,我有一个带有隔离级别可序列化的事务(由方式仅适用于该交易,还是应该在提交交易后将其设置回来?):
我想知道是否有更好的方法来确保数字被使用一次,并且在表被锁定的情况下增加数量(只有数字表被锁定,对吧?)。
我读到了关于sp_getapplock的内容,这对实现我的目标有点好吗?
答案 0 :(得分:1)
我会优化更新例程(并单独处理“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 Server将确保在递增之前没有两个事务读取相同的值。
如果您不想单独处理插件,可以:
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
相同的防范竞争条件,但出于某种原因,我不记得证据在哪里。
答案 1 :(得分:0)
如果您先插入然后更新,则会有一个时间窗口,其中设置了无效的数字并且可以观察到。此外,如果第二次交易失败,那么总是会发生不一致的数据。
试试这个:
这样你可以刻录一个数字,但永远不会有不一致的数据。