如何在SQL Server上强制执行SELECT阻塞?

3

我看到了很多关于避免阻塞的信息。但我的情况是,我需要阻塞。

我们有一张表,两个独立进程将使用它进行通信。这些进程将在随机时间运行,并使用此控制表来了解另一个进程是否正在忙碌。由于两个进程不能同时忙碌,因此需要控制表。

每个作业在运行时都会检查控制表...并基于该数据决定是否可以运行,如果可以,则会更新控制表记录。

问题在于,如果两个进程同时运行,不清楚它们是否会执行以下不希望的操作(按照精确顺序):

  1. Proc A 读取控制表(表格显示可以进行)
  2. Proc B 读取控制表(表格显示可以进行)
  3. Proc A 更新控制表(表格现在显示“Proc A正在忙碌”)
  4. Proc B 更新控制表(表格现在显示“Proc B正在忙碌”)

<- 在这种情况下,两个进程都认为它们成功地更新了控制表并开始了它们的主要流程(这不是我们想要的)

我想要的是让Proc B被阻止从控制表中进行选择(而不仅是更新)。这样,当Proc B的查询最终起作用时,它将看到已更新的“忙碌”值,而不是被Proc A更改之前存在的值。

我们正在使用SQL Server 2008 R2。我查看了可串行化隔离,但似乎不够强大。

就价值而言,我们正在尝试使用JDBC实现这一点...使用conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

我们理解为最高级别的隔离,但我仍然可以在另一个窗口中运行选择。

我100%确定这绝不是一个独特的问题....有人有任何建议使其正常工作吗?


这可能有所帮助:https://dev59.com/v3RA5IYBdhLWcg3w2x6W#798234 - KM.
2个回答

1
您的方法是可行的,但需要考虑以下几点:
  1. 您需要在最开始(第一次读取之前)开启一个事务,并且只有在完成工作后才能提交。

  2. 如果A和B都尝试读取/修改同一条记录,则可以直接使用默认事务隔离级别(READ COMMITTED)。否则,您需要告诉SQL Server锁定整个表(使用TABLOCK提示)。

  3. 实际上,您根本不需要进行读取操作!

以下是它的工作原理:

     P1                 P2
 ---------------------------------
  BEGIN TRANS
                     BEGIN TRANS
  WRITE (success)
                     WRITE (blocked)
  do work            |
  .                  |
  .                  | 
  COMMIT     ->      block released, WRITE finishes

                     do work
                     . 
                     .
                     COMMIT

注:需要注意的是,SQL Server支持应用程序锁。因此,如果您只想同步两个进程,您不需要“滥用”表格:

补充一下,让我也回答一下标题中的问题(“如何强制SQL Server上的SELECT阻塞?”):为此,您可以使用HOLDLOCKXLOCK表提示的组合(或者使用TABLOCKX,如果您想独占锁定整个表)。


JDBC似乎不支持TABLOCK...至少我拥有的驱动程序不支持。 话虽如此,您的解决方案完全正确。我们很愚蠢,试图在没有事务的SSMS窗口中进行测试...当我们在两端同时运行具有事务的进程时,一个失败了。 因此,感谢您的帮助。 这肯定也会帮助其他人。 - iluomo

0
如果你需要读取(因为你想要进行一些处理),我会按照以下步骤进行:
Set transaction isolation level serializable
begin transaction
 select from tablea  
 update tablea
commit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接