We are trying to implement a system for "checking out" records from our SQL Server 7.0 database.
In this distributed application, the client machine needs to select an available record from tblSpool (where the record's Status is -1) and then set its status to 0 to indicate that it has been checked out. The main problems encountered in my stress testing are that: A)the same record is being handed out to more than one computer at a time, B)EOFs are being returned when there really are more available records, or C)deadlocking.
I've explored dozens of possible combinations setting isolation levels and with locking hints in the FROM (WITH) clause, all with no success. Since there will potentially be dozens of computers all contending to "check out" a record at once, we need this to work properly. Here is the (simplified) code of my stored procedure:
CREATE PROCEDURE sp_CheckRecordOut
@ClientID int
AS
BEGIN
DECLARE @theRecord int
BEGIN TRANSACTION
/***** determine next available record *****/
SELECT TOP 1 @theRecord = RecordID FROM tblSpool
-- ugh, i sure have tried a bunch of these combinations, none with success
--WITH (UPDLOCK, HOLDLOCK)
--WITH (HOLDLOCK, ROWLOCK, UPDLOCK, READPAST)
--WITH (UPDLOCK, ROWLOCK, READPAST)
--WITH (UPDLOCK, READPAST)
--WITH (UPDLOCK, ROWLOCK)
WHERE StatusID = -1
/***** "Check it out" *****/
UPDATE tblSpool SET StatusID = 0, ClientID = @ClientID
WHERE RecordID = @theRecord
COMMIT TRANSACTION
/***** now we can return the 'checked out' RecordID to client machine*****/
SELECT @theRecord AS 'theRecord'
END
I've read about strategies using a semaphore/timestamp column to help with situations similar to this, but don't see how that might help me here. Thank you for any assistance or guidance!
In this distributed application, the client machine needs to select an available record from tblSpool (where the record's Status is -1) and then set its status to 0 to indicate that it has been checked out. The main problems encountered in my stress testing are that: A)the same record is being handed out to more than one computer at a time, B)EOFs are being returned when there really are more available records, or C)deadlocking.
I've explored dozens of possible combinations setting isolation levels and with locking hints in the FROM (WITH) clause, all with no success. Since there will potentially be dozens of computers all contending to "check out" a record at once, we need this to work properly. Here is the (simplified) code of my stored procedure:
CREATE PROCEDURE sp_CheckRecordOut
@ClientID int
AS
BEGIN
DECLARE @theRecord int
BEGIN TRANSACTION
/***** determine next available record *****/
SELECT TOP 1 @theRecord = RecordID FROM tblSpool
-- ugh, i sure have tried a bunch of these combinations, none with success
--WITH (UPDLOCK, HOLDLOCK)
--WITH (HOLDLOCK, ROWLOCK, UPDLOCK, READPAST)
--WITH (UPDLOCK, ROWLOCK, READPAST)
--WITH (UPDLOCK, READPAST)
--WITH (UPDLOCK, ROWLOCK)
WHERE StatusID = -1
/***** "Check it out" *****/
UPDATE tblSpool SET StatusID = 0, ClientID = @ClientID
WHERE RecordID = @theRecord
COMMIT TRANSACTION
/***** now we can return the 'checked out' RecordID to client machine*****/
SELECT @theRecord AS 'theRecord'
END
I've read about strategies using a semaphore/timestamp column to help with situations similar to this, but don't see how that might help me here. Thank you for any assistance or guidance!