SQL Server竞争条件问题

前端之家收集整理的这篇文章主要介绍了SQL Server竞争条件问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
(注意:这适用于MS sql Server)

假设您有一个带有主键标识列和CODE列的表ABC.我们希望这里的每一行都有一个独特的,顺序生成代码(基于一些典型的校验位公式).

假设您有另一个表DEF只有一行,它存储下一个可用的CODE(想象一个简单的自动编号).

我知道下面的逻辑会出现竞争条件,其中两个用户最终可能会使用相同的代码

1) Run a select query to grab next available code from DEF
2) Insert said code into table ABC
3) Increment the value in DEF so it's not re-used.

我知道,两个用户可能会陷入第1步),最终可能会在ABC表中找到相同的CODE.

处理这种情况的最佳方法是什么?我以为我可以围绕这个逻辑包装一个“begin tran”/“commit tran”,但我认为这不起作用.我有一个这样的存储过程来测试,但是当我从MS中的两个不同的窗口运行时,我没有避免竞争条件:

begin tran

declare @x int

select   @x= nextcode FROM  def

waitfor delay '00:00:15'

update def set nextcode = nextcode + 1

select @x

commit tran

有人可以对此有所了解吗?我认为该事务会阻止其他用户在第一个事务完成之前能够访问我的NextCodeTable,但我想我对事务的理解是有缺陷的.

编辑:我尝试将等待移到“更新”声明后,我有两个不同的代码…但我怀疑.我在那里有waitfor声明来模拟延迟,因此可以很容易地看到竞争条件.我认为关键问题是我对交易如何运作的错误认识.

解决方法

将事务隔离级别设置为Serializable.
在较低的隔离级别,其他事务可以读取此事务中读取(但尚未修改)的行中的数据.因此,两个事务确实可以读取相同的值.在隔离度非常低(Read Uncommitted)时,其他事务甚至可以在修改后(但在提交之前)读取数据…

查看有关sql Server隔离级别here的详细信息

因此,底线是隔离级别在这里是一个重要的部分来控制其他事务进入这个访问的访问级别.

注意.从link开始,关于Serializable
语句无法读取已修改但尚未由其他事务提交的数据.
这是因为在修改行时放置锁,而不是在Begin Trans发生时放置,所以你所做的可能仍然允许另一个事务读取旧值,直到修改它为止.所以我会改变逻辑,在你读取它的同一个语句中修改它,从而同时锁定它.

begin tran
declare @x int
update def set @x= nextcode,nextcode += 1
waitfor delay '00:00:15'
select @x
commit tran
原文链接:https://www.f2er.com/mssql/84082.html

猜你在找的MsSQL相关文章