【问题标题】:T-SQL transactions and table lockingT-SQL 事务和表锁定
【发布时间】:2009-12-23 02:08:28
【问题描述】:

如果我想选择表中尚未处理的所有记录,然后更新这些记录以反映它们已被处理,我会执行以下操作:

 SELECT * FROM [dbo].[MyTable] WHERE [flag] IS NULL;
 UPDATE [dbo].[MyTable] SET [flag] = 1 WHERE [flag] IS NULL;

如何确保 UPDATE 仅适用于我刚刚选择的记录,即,防止在我的 SELECT 之后但在我的 UPDATE 之前由另一个进程添加的任何可能已添加 [flag] = NULL 的记录的 UPDATE ?我可以将这两个语句包装在一个事务中吗?我必须在桌子上放一把锁吗?

【问题讨论】:

    标签: sql sql-server tsql transactions locking


    【解决方案1】:

    单次调用,使用 OUTPUT 子句无需事务。

    XLOCK 独占锁定行以停止并发读取(例如,另一个进程正在寻找 NULL 行)

    UPDATE dbo.MyTable WITH (XLOCK)
    SET flag = 1 
    OUTPUT INSERTED.*
    WHERE flag IS NULL;
    

    【讨论】:

    • 最早支持OUTPUT子句的SQL Server版本是什么?
    • ..鉴于其他问题,OP 也使用 SSIS。
    • 是的,我对 2k5 很感兴趣,抱歉,我应该提到这一点。就我而言,这看起来像是赢家——谢谢!
    【解决方案2】:

    使用 OUTPUT 子句从 UPDATE 本身返回结果集:

    UPDATE [dbo].[MyTable] 
    SET [flag] = 1 
    OUTPUT INSERTED.*
    WHERE [flag] IS NULL;
    

    【讨论】:

      【解决方案3】:

      用途:

      SELECT * 
        FROM [dbo].[MyTable] (UPDLOCK)
       WHERE [flag] IS NULL;
      
      UPDATE [dbo].[MyTable] 
         SET [flag] = 1 
       WHERE [flag] IS NULL;
      

      有关锁定提示的更多信息:

      【讨论】:

      • +1。请注意,这需要在事务中才能使更新锁传递到更新语句。
      • 还有 2 个语句,但 SQL Server 2005 + 不需要这些语句
      【解决方案4】:

      您可以将这两个语句包装在具有 read_committed 或更受限制范围的事务中。它有点贵,可能会导致其他问题。 King 的解决方案更可行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-18
        • 2010-09-28
        • 1970-01-01
        • 1970-01-01
        • 2019-06-30
        • 2016-12-08
        • 1970-01-01
        • 2013-11-19
        相关资源
        最近更新 更多