Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Server 2008: SELECT FOR UPDATE

I have seen a question on here about this however it was old so I will ask again in case a solution now exists.

My issue is this. I have a database table which I wish to select from but I want to lock the rows that I have selected. The reason for this is that I may have another process running that will also want to select the same rows and I want to prevent this.

Imagine I have two processes doing the same thing. One performs a select and begins to perform its processing of the data. Then a few seconds later the next process comes along and does a select but because the rows aren't locked it also takes the same records and begins to process them. This is of course a bad situation to be in. In Oracle you can use SELECT FOR UPDATE which will take out a lock on the rows to prevent them from being used by the 2nd process. How can this be achieved in SQL Server 2008?

I should add that I can only use standard sql statements. I do not have access to procedures, functions etc. It has to be done via a simple statement. Its a long story and a design consideration that has been taken out of my hands. The solution must be able to be stored in a table, retrieved later and then run via the ADO objects in C# in particular assigned to a command object.

How can a lock be applied to this statement?

SELECT * 
FROM 
  (SELECT TOP (20) * 
   FROM [TMA_NOT_TO_ENTITY_QUEUE]  
   WHERE [TMA_NOT_TO_ENTITY_QUEUE].[STATE_ID] = 2 
   ORDER BY TMA_NOT_TO_ENTITY_QUEUE.ID) a
like image 975
CSharpened Avatar asked Dec 08 '22 22:12

CSharpened


2 Answers

You need to use one of the so-called table hints:

The update lock prevents other processes from attempting to update or delete the rows in question - but it does not prevent read access:

    SELECT TOP (20) * 
    FROM [TMA_NOT_TO_ENTITY_QUEUE] WITH (UPDLOCK)
    WHERE [TMA_NOT_TO_ENTITY_QUEUE].[STATE_ID] = 2 
    ORDER BY TMA_NOT_TO_ENTITY_QUEUE.ID

There's also an exclusive lock, but basically, the update lock should be enough. Once you've selected your rows with an update lock, those rows are "protected" against updates and writes until your transaction ends.

like image 120
marc_s Avatar answered Jan 01 '23 09:01

marc_s


by lock, what do you want to happen with the second process? If you want it to wait until the first finishes, you can totally do that using transaction isolation level.

try running this small test and you will understand:

Open a two new queries on SSMS (lets call it A and B from now one) and on A, create a simple table like this:

create table transTest(id int)
insert into transTest values(1)

now, do the following:

do select * from transTest in both of them. You will see the value 1

On A run:

set transaction isolation level read committed

On B run:

begin transaction
insert into transTest values(2)

On A run:

select * from transTest

you will see that the query wont finish because it is locked by the transaction on B

On B run:

commit transaction

Go back to A and you will see that the query finished

Repeat the test with set transaction isolation level read uncommitted on A you will see that the query wont be locked by the transaction

like image 28
Diego Avatar answered Jan 01 '23 07:01

Diego