I basically have an application that has, say 5 threads, which each read from a table. The query is a simple SELECT TOP 1 * from the table, but I want to enforce a lock so that the next thread will select the next record from the table and not the locked one. When the application has finished it's task, it will update the locked record and release the lock and repeat the process again. Is this possible?
+5
A:
The kind of approach I'd recommend is to have a field in the record along the lines of that indicates whether the record is being processed or not. Then implement a "read next from the queue" sproc that does the following, to ensure no 2 processes pick up the same record:
BEGIN TRANSACTION
-- Find the next available record that's not already being processed.
-- The combination of UPDLOCK and READPAST hints makes sure 2 processes don't
-- grab the same record, and that processes don't block each other.
SELECT TOP 1 @ID = ID
FROM YourTable WITH (UPDLOCK, READPAST)
WHERE BeingProcessed = 0
-- If we've found a record, set it's status to "being processed"
IF (@ID IS NOT NULL)
UPDATE YourTable SET BeingProcessed = 1 WHERE ID = @ID
COMMIT TRANSACTION
-- Finally return the record we've picked up
IF (@ID IS NOT NULL)
SELECT * FROM YourTable WHERE ID = @ID
For more info on these table hints, see MSDN
AdaTheDev
2010-02-19 10:10:48
Thanks for the quick response. Would I have to do the Update statement straight away? If I commited the transaction after the SELECT, would that leave the LOCK in place?
Ardman
2010-02-19 10:20:25
No the lock wouldn't remain in place.
AdaTheDev
2010-02-19 10:30:53
Yes, this is SQL Server, 2008 to be precise. So, I'd need to start a transaction within the application, select the record, do the processing necessary in the application and the update the record and commit the transaction in order to keep the row locked?
Ardman
2010-02-19 10:34:37
If you don't want to have the "BeginProcessed" flag, then yes. This approach above, is the recommended way to do this kind of queue processing. Alternatively, you could use something like MSMQ
AdaTheDev
2010-02-19 10:40:35
Thank you. Will give it a go :o)
Ardman
2010-02-19 10:59:37
would you want to also use ROWLOCK so other processes would get rows on the same page?
KM
2010-02-19 15:54:24
I'm not sure you need to specify ROWLOCK as it should just get a row lock anyway (only doing a TOP 1)?
AdaTheDev
2010-02-19 16:06:48