【问题标题】:How to lock a SELECted rows in Sql Server until transaction is COMMITTED in a Stored Procedure如何锁定 Sql Server 中的选定行,直到事务在存储过程中被提交
【发布时间】:2016-10-03 05:22:37
【问题描述】:

我想在 SP 中使用 SELECT 语句锁定表中的某些行。我的 SP 中有交易。我想在 BEGIN TRANSACTION 之后锁定我选择的所有行。所以,我想在 COMMIT/ROLLBACK 之后释放这些行。

我尝试过 XLOCK、UPDLOCK、HOLDLOCK,但它们都没有达到我的预期。

这是我的示例代码...

BEGIN TRANSACTION 
    -- I WANT TO LOCK EMPLOYEES LIVE IN ISTANBULL
    SELECT ID FROM EMPLOYEES WITH(XLOCK) WHERE CITY='ISTANBUL'
    ....
    ....
    ....
COMMIT
-- LOCKED ROWS SHOULD BE RELEASED AFTER COMMIT.

有什么建议吗?

【问题讨论】:

    标签: sql sql-server stored-procedures transactions


    【解决方案1】:

    您的代码应该可以正常工作。

    假设,您正在使用 UPDLOCK/XLOCK 选择行。

    第一笔交易

    BEGIN TRAN
    SELECT ID FROM EMPLOYEES WITH(UPDLOCK, XLOCK) WHERE CITY='ISTANBUL'
    --COMMIT TRAN (Stopping commit to keep the lock running)
    

    现在尝试在另一个窗口中运行以下操作。

    第二次交易

    BEGIN TRAN
    SELECT ID FROM EMPLOYEES WITH(UPDLOCK, XLOCK) WHERE CITY='ISTANBUL'
    COMMIT TRAN
    

    在您提交第一笔交易之前,您的第二笔交易将无法选择。因为多个 UPDLOCK 或 XLOCK 不能同时应用于一个资源。

    现在,如果您读取行而不使用未提交的第一个事务锁定,那么第二个事务将不会被第一个事务阻止。

    第二次交易

    BEGIN TRAN
    SELECT ID FROM EMPLOYEES WHERE CITY='ISTANBUL'
    COMMIT TRAN
    

    因为在第二个事务中没有应用锁,所以它不会被第一个事务 UPDLOCK 或 XLOCK 阻止。

    现在为了防止任何读取与其他读取,您需要将 ISOLATION LEVEL 更改为 SERIALIZABLE。

    第一笔交易

    BEGIN TRAN
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE  
    SELECT ID FROM EMPLOYEES WHERE CITY='ISTANBUL'
    --COMMIT TRAN (Stopping commit to keep the lock running)
    

    第二次交易

    BEGIN TRAN
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
    SELECT ID FROM EMPLOYEES WHERE CITY='ISTANBUL'
    COMMIT TRAN
    

    现在第二笔交易将被第一笔交易阻塞。虽然在读取期间没有应用锁,但在事务隔离级别 SERIALIZABLE 中,读取事务将阻止读取同一资源上的另一个事务。

    现在,如果您使用 NOLOCK 进行选择,则不存在阻止您的事务锁或隔离级别。

    希望这些帮助:)

    【讨论】:

    • 我有一个巨大的系统,已经运行了很长时间。不幸的是,所有这些事务都是在没有 UPDLOCK 和 XLOCK 的情况下编写的。这就是我遇到困难的原因
    • @ayilmaz,几个月前我也遇到过这些问题。要停止另一个读取,您有两个选择,要么对每个地方使用锁定,要么使用 SERIALIZABLE 隔离级别。但我会建议你使用 UPDLOCK 而不是改变隔离级别。它会增加您的重新开发成本,但更改隔离级别会对性能产生巨大影响。并删除所有 NOLOCK(如果使用)。
    • 另外,如果您要稍后在同一事务中更新同一资源,我想建议您使用带有 select 的 UPDLOCK。它将防止更新行的常见死锁问题。
    • 那你别无他法我的朋友。搜索它们,查看它们并在需要时附加 UPDLOCK。
    【解决方案2】:
    FROM TABLE_ITEM with (updlock, holdlock)
    

    【讨论】:

      【解决方案3】:

      将 holdlock 提示添加到 xlock 提示中。

      例如。

      begin tran 
        select ... from ... with (xlock, holdlock) where ...
      commit tran
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-06
        • 1970-01-01
        相关资源
        最近更新 更多