We have an ASP.NET/MSSQL based web app which generates orders with sequential order numbers.
When a user saves a form, a new order is created as follows:
- SELECT MAX(order_number) FROM order_table, call this max_order_number
- set new_order_number = max_order_number + 1
- INSERT a new order record, with this new_order_number (it’s just a field in the order record, not a database key)
If I enclose the above 3 steps in single transaction, will it avoid duplicate order numbers from being created, if two customers save a new order at the same time? (And let’s say the system is eventually on a web farm with multiple IIS servers and one MSSQL server).
I want to avoid two customers selecting the same MAX(order_number) due to concurrency somewhere in the system.
What isolation level should be used? Thank you.
Using an identity is by far the best idea. I create all my tables like this:
The “identity” flag means, “Let SQL Server assign this number for me”. The (1, 1) means that identity numbers should start at 1 and be incremented by 1 each time someone inserts a record into the table. Not Null means that nobody should be allowed to insert a null into this column, and “primary key” means that we should create a clustered index on this column. With this kind of a table, you can then insert your record like this:
But to answer your literal question, I can give a lesson about how transactions work. It’s certainly possible, although not optimal, to do this:
Just keep in mind that declaring your table with an identity primary key column does this all for you automatically.