ayilmaz ayilmaz - 2 months ago 15
SQL Question

How to lock a SELECted rows in Sql Server until transaction is COMMITTED in a Stored Procedure

I would like to lock some rows in a table with a SELECT statement in SP. I have transaction in my SP. I would like to lock all rows that I SELECT after BEGIN TRANSACTION.So, I would like to release those rows after COMMIT/ROLLBACK.

I have tried XLOCK,UPDLOCK,HOLDLOCK but none of them does what I expect.

Here is my sample code...

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.


any suggestion?

Answer

Your code should work fine.

Suppose, you are selecting rows with UPDLOCK/XLOCK.

First Transaction

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

Now try run following in another window.

Second Transaction

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

Your second transaction will not be able to select until you commit your first transaction. Because multiple UPDLOCK or XLOCK can't be applied together on a resource.

Now, if you read rows without locking with uncommitted first transaction then second transaction will not be prevented by the first.

Second Transaction

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

Because in second transaction no lock applied so it will not be prevented by first transactions UPDLOCK or XLOCK.

Now to prevent any read with another read you need to change your ISOLATION LEVEL TO SERIALIZABLE.

First Transaction

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

Second Transaction

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

Now second transaction will be blocked by first transaction. Though no lock applied during read but in transaction isolation level SERIALIZABLE a read transaction will block read of another transaction over same resource.

Now If you select with NOLOCK then there is no transaction lock or isolation level exists to block you.

Hope these helps :)

Comments