Need to prevent race condition during select and update

I am using SQL Server 6.5 and I have a stored procedure that creates a sales number by incrementing the last one used.
I store that information in a table called  LastSalesNumber.  This function worked fine for over a
year but I am now having problems with an increase in traffic and users.  I have had at least two occasions where it appears that two users made sales at the very same time and two different sales records were created with the same number.  What changes should I make to the following code in the form of locking or restructuring to ensure that this doesn't happen anymore?


-- begin snippet
/* Assign Sales number to be last sales number assigned + 1  */

select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber + 1)
     from LastSalesNumber


/*  increment the last Sales number assigned  */

update LastSalesNumber
     set LastNumber = LastNumber + 1

-- end snippet
LVL 1
geowilliAsked:
Who is Participating?
 
Guy Hengel [angelIII / a3]Connect With a Mentor Billing EngineerCommented:
The problem is atomicity, which can be solved using transactions:

begin transaction
/* Assign Sales number to be last sales number assigned + 1  */

select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber + 1)
    from LastSalesNumber


/*  increment the last Sales number assigned  */

update LastSalesNumber
    set LastNumber = LastNumber + 1

commit transaction


This will make that if a first user is inside this transaction, any other user will have to wait until that one has finished. Using your code, they can immediately go on...

Cheers
0
 
Anthony PerkinsCommented:
Since there is no implict row locking in SQL Server 6.5 you may want to try reversing the statements:

In other words, update first
update LastSalesNumber
    set LastNumber = LastNumber + 1

And then Select:
select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber)
    from LastSalesNumber

Here the problem may be the reverse: "gaps" in your sales numbers.
0
 
nigelrivettCommented:
Unfortunately with this code there is nothing to stop two spids getting the same sales number as

select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber + 1)
   from LastSalesNumber

will take a shared lock which is compatible with another shared lock and the lock will be released immediately.
Code that will work is

update LastSalesNumber
set LastNumber = LastNumber + 1 ,
@SalesNumber = "SLS-" + convert(varchar(13), LastNumber + 1)

or
begin tran
update LastSalesNumber
   set LastNumber = LastNumber + 1

select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber)
from LastSalesNumber
commit tran

commit transaction
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
nigelrivettCommented:
update LastSalesNumber
   set LastNumber = LastNumber + 1

select @SalesNumber = "SLS-" + convert(varchar(13), LastNumber)
   from LastSalesNumber

This doesn't work either without the transaction as two spids could do the update before both getting the same number.
0
 
geowilliAuthor Commented:
Thanks for the answer and brief explanation
0
 
nigelrivettCommented:
um.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.