如何在存储过程中提交事务之前锁定 Sql Server 中的选定行

Ari*_*MAZ 0 sql sql-server stored-procedures transactions

我想用 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.
Run Code Online (Sandbox Code Playgroud)

有什么建议吗?

Est*_*sty 5

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

假设您正在选择带有 UPDLOCK/XLOCK 的行。

第一笔交易

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

现在尝试在另一个窗口中运行。

第二笔交易

BEGIN TRAN
SELECT ID FROM EMPLOYEES WITH(UPDLOCK, XLOCK) WHERE CITY='ISTANBUL'
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)

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

现在,如果您使用未提交的第一个事务在没有锁定的情况下读取行,那么第一个事务不会阻止第二个事务。

第二笔交易

BEGIN TRAN
SELECT ID FROM EMPLOYEES WHERE CITY='ISTANBUL'
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)

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

现在为了防止任何读取与另一个读取,您需要将隔离级别更改为可序列化。

第一笔交易

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

第二笔交易

BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
SELECT ID FROM EMPLOYEES WHERE CITY='ISTANBUL'
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)

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

现在,如果您选择NOLOCK,则不存在事务锁或隔离级别来阻止您。

希望这些有帮助:)