插入依赖读取时处理并发

vic*_*tor 6 sql-server concurrency azure-sql-database

[短的]

我有以下情况:用户A尝试将数据DA插入数据库。要检查是否A允许用户插入DA,我需要运行查询并进行一些计算。我遇到的问题是,当我进行计算时,另一个用户 ( B) 也尝试将数据插入到数据库中。现在,假设两个用户在插入新数据之前都读取了计算所需的信息,那么他们可能都被清除插入,而来自用户的数据A将禁止用户B插入,从而使数据库处于不一致状态。

如何在 Azure SQL 数据库 V12 中解决这种并发问题?

[详细的]

用户插入的数据是时间间隔的开始和结束,例如start: 6:00, end: 7:00。要求是不能有时间间隔重叠。这意味着区间start: 6:00, end: 9:00start: 5:00, end: 6:00不能同时存在。目前我正在做的是检查是否有任何行与用户尝试使用以下查询插入的新间隔重叠:

SELECT COUNT(*) FROM [Table1] WHERE Start <= attempEnd && End >= attemptStart
Run Code Online (Sandbox Code Playgroud)

现在,问题是多个用户可能试图插入一个间隔,而这些新间隔可能相互重叠。但是,在上面的查询运行时,此信息可能不可用,这会导致插入重叠间隔。

如何在 Azure SQL 数据库 V12 中解决这种并发问题?

Mic*_*een 1

问题在于,A 的事务结束时可能存在一些值(由 B 插入的值),而 A 第一次检查时这些值并不存在。这被称为幻影

幻影是与搜索条件匹配但最初未看到的行。

防止幻像的方法是使用可串行化隔离级别。这是唯一可以防止幻象的隔离级别。

还有其他方法可以在不使用该隔离级别的情况下序列化工作负载。一种是使用TABLOCKX获取整个表的排他锁。当在显式事务(BEGIN TRANSACTION)中使用时,这将在表上获取独占锁并保持它,直到事务提交或回滚。因此,在 A 提交之前,B 将无法插入。然而,表锁会影响所有工作,包括不会引起间隔重叠的简单查询。

更细粒度的方法是使用sp_getapplock。这允许您的代码使用自己的语义生成自己的锁。它充当互斥体。当工作负载 A 启动时,它会获取此应用锁。然后它可以继续执行检查并插入,确信它自己有权这样做。如果工作负载 B 同时启动,它将尝试获取应用锁并被阻止,因为该应用锁归 A 所有。您必须小心,所有可能受到重叠间隔问题影响的工作都必须通过获取此自定义应用锁来启动,并且释放它即可完成。写入不会受到间隔重叠问题的影响,并且所有读取都可以继续进行,而无需获取应用锁或被应用锁阻止。