I\'ve got 100 threads that are each calling the stored procedure as defined below.
How do I prevent dirty reads?
SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS
Bacon Bits beat me to it, but using the OUTPUT
clause will be the easiest way to work around your racing issue. Off course locking is an option too, although I think it will have slightly higher overhead. That said, using an IDENTITY
column or a SEQUENCE
is so much easier than trying to implement this functionality manually.
I took the liberty of putting the answer in your code and add a few remarks:
SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS OFF
GO
ALTER procedure GetNextCerealIdentity(@NextKey int output,@TableID int)
AS
set nocount on
DECLARE @RowCount int, @Err int
DECLARE @output TABLE (NextKey int)
begin transaction
/*Update CfgCerealNumber Table */
UPDATE CfgCerealNumber WITH (UPDLOCK)
Set CerealNumber = CerealNumber + 1
OUTPUT inserted.CerealNumber INTO @output (NextKey)
WHERE CerealNumberID = @TableID
select @RowCount = @@RowCount, /*Obtain updated Cereal number previously incremented*/
@Err = @@Error
if @Err <> 0 /* If Error gets here then exit */
begin
Rollback Transaction
raiserror ('GetNextCerealIDSeries Failed with Error: %d TableID: %d ', 16,1, @Err, @TableID)
return -1
end
if @RowCount = 0 /* No Record then assume table is not */
/* been initialized for TableID Supplied*/
begin
Rollback Transaction
raiserror ('No Table Record Exists in CfgCerealNumber for ID:%d ', 16,1, @TableID)
return -1
end
COMMIT TRANSACTION
/*Obtain updated Cereal number previously incremented*/
SELECT @NextKey = NextKey
From @output
return 0
GO
Remarks:
SET NOCOUNT OFF
again before exiting the stored procedure. As you go out of scope this setting will return back to what it was before you entered the stored procedure.WITH (UPDLOCK)
, but it certainly won't hurt.ROLLBACK
and then do a RaisError()
simply because the latter might cause the connection to be dropped by some client-software and/or you might be inside a TRY...CATCH
. Both will break the flow of the commands and you'll end up with transaction count mismatch.