H
Hugo Kornelis
Hi Hugo,
I have a question about the "retry" section.
The only other UNIQUE constraint is the ID column, but that's an
IDENTITY column, so it will be unique.
You mentioned that "even under the most extreme concurrency
conditions, you will eventually succeed in entering a row with the
retrieved scope_identity() before another connection does. "
But, in my SP the scope_identity() is outside the "retry" section.
The "retry" section I only use ident_current('HistTradesOrig').
So, do you still think that there is no way for the loop to go
forever ?
Thanks, Hugo
BEGIN TRANSACTION;
retry:
BEGIN TRY;
SELECT @expected_id = ident_current('HistTradesOrig') + 1
SELECT @order = @account + '-' + CAST(@expected_id AS varchar(50))
insert into HistTradesOrig
([Floor],[Order],...)
values
(@Floor,@Order,...)
END TRY
BEGIN CATCH;
SELECT @ErrNumber = ERROR_NUMBER()
IF @ErrNumber = 2627
BEGIN;
GOTO retry
END;
ELSE
BEGIN;
SET @ErrMsg = '1.' + ERROR_MESSAGE() + ' ' + @order
RAISERROR (@ErrMsg, 16, 1);
END;
END CATCH
select @ID = SCOPE_IDENTITY()
IF @id <> @expected_id
BEGIN
UPDATE HistTradesOrig
SET [Order] = @ACCOUNT + '-' + CAST(@ID AS varchar(50))
WHERE ID = @ID
END
SET @Success = 1
COMMIT TRANSACTION;
Hi fniles,
Okay, let's use an example. Let's say that we want to add a row for
@account 'XYZ'. The last created identity value for HistTradesOrig is
123456. In the try, you first retrieve this value and add 1 to get the
expected next identity value (123457). You use this number to
precompute the order ('XYZ123457'), then insert the row.
If there was a concurrent insert from this same stored procedure that
executed the INSERT just a tad earlier, it will attempt to insert a
row with the same order (and a value of 123458 for the identity
column). The result is that this insert will run into a violation of
the unique constraint on the order column; control moves to the catch
block, that will cause the processing to start from scratch.
On the retry, the last used identity is 123458, so the expected id is
calculated as 123459. The order column is precomputed as 'XYZ123459',
and the row is inserted. If this time there was a concurrent insert
from another procedure, that uses different logic for the order
column, the insert will succeed - there is no collission on the order
column, and the IDENTITY column will simply get the next available
column. So we insert a row with IDENTITY value 123460, and order
'XYZ123459'.
After the TRY CATCH, the last generated IDENTITY for this connection
(which is the IDENTITY value of the row just inserted) is retrieved,
and compared to the expected value. If it matches, we're good and the
logic ends. In this case, because of the concurrent insert from the
other stored procedure, there is a difference, so now you update the
just inserted row to change the precomputed (but in this case
incorrect) order value to the correct value.
Had there been no concurrent insert, then SCOPE_IDENTITY would have
matched the expected ID, and the UPDATE would have been skipped. This
will probably be the most common execution pattern.