【问题标题】:How to skip rows from getting selected in SQL如何跳过在 SQL 中被选中的行
【发布时间】:2022-01-11 13:12:53
【问题描述】:

如何跳过被选中的持有锁的行?

Begin tran

Select * 
From table with(holdlock) 
Where id = 2

在第二个会话中,当查询被执行时,应该跳过结果中 id 值为 2 的行。

【问题讨论】:

  • 这闻起来像 XY problem。我建议您研究“乐观并发”和“悲观并发”这两个术语,花一些时间了解锁定的一般工作原理,然后确定您的实际目标是什么以及如何最好地实现它。如果您尝试将表用作队列,可以找到讨论。

标签: sql sql-server tsql transactions


【解决方案1】:

我在第二次会话中使用以下代码实现了这一点。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READS
Select * from table WITH (Readpast)

感谢大家的帮助。

【讨论】:

    【解决方案2】:

    (holdlock) 持有锁直到事务结束 - 但这是一个共享锁 - 例如其他读者不会被该锁阻止 ...

    如果你真的必须这样做,你需要建立(并保持)一个排他锁

    Begin tran
    
    Select * 
    From table with (updlock, holdlock) 
    Where id = 2
    

    并在第二个会话中使用WITH (READPAST) 子句,不要被排他锁停止。

    PS:根据@charlieface 的推荐更新为使用updlock - 谢谢!

    【讨论】:

    • UPDLOCK 可能比XLOCK 更好,这意味着读者仍然可以阅读,但另一个UPDLOCK 被屏蔽了
    • 感谢您的回复,但这个技巧不起作用。作为第二个会话,所有数据仍在加载结果并带有 readpast 提示。
    【解决方案3】:

    READPAST 将跳过现有的锁。 但是你需要另一个锁提示,否则SELECT 不会保留锁。

    XLOCK, HOLDLOCK(又名SERIALIZABLE)是一个选项,但可以是限制性的。

    您可以使用UPDLOCK 来保持锁定直到事务结束。 UPDLOCK 生成一个U 锁,它阻止其他UX(独占写入器)锁,但仍允许S 读取器锁。所以数据仍然可以被只读进程读取,但是执行相同代码的另一个进程仍然会被阻塞。

    Begin tran
    
    Select * 
    From table WITH (UPDLOCK, READPAST) 
    Where id = 2
    
    -- etc
    

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 感谢您的回复,但 readpast 提示在进行插入/更新/删除活动时有效,这里只有选择过程。我也试过了,但没有用。
      猜你喜欢
      • 1970-01-01
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      相关资源
      最近更新 更多