ads by Microsoft Corporation is licensed under Source EULA
Transact SQL (T-SQL) statements are used to create Microsoft SQL Server Stored Procedures.
Stored Procedures are maintained in the database making it easier to apply updates that improve the performance of all client applications.
Stored Procedures that help customers to purchase cinema tickets or reserve seats on airplanes need to be written with isolation levels in mind.
Consider how a stored procedure might be used to shuffle the contents of a table representing a deck of playing cards.
Using cross join to create a table the represents a standard deck of playing cards
To shuffle a deck of standard playing cards we could select any two cards from the deck at random and swap their positions. If we did this enough times the deck would be shuffled.
Here is a stored procedure that will swap the data in two rows of the deck table.
SwapCardsV1
To test the SwapCards stored procedure we can create:
SwapCards T-SQL Client Code
Running a single copy of client code that calls the SwapCardV1 stored procedure is fine.
The result is a shuffled deck with 13 cards of each suit.
Shuffle results single client
However, running multiple copies of the client code that calls the SwapCardV1 stored procedure reveals an issue.
Shuffle failure
When concurrency is introduced our original SwapCards stored procedure does not work. No errors are being raised but transactions are stepping on each other.
We can use Snapshot isolation to address the issue.
SwapCards (with snapshot isolation)
With the updated SwapCard stored procedure we can run multiple updates concurrently.
Shuffle success
Snapshot isolation guarantees that reads made in a transaction will see a consistent snapshot of the database and that the transaction will commit only if no update made in the transaction conflicts with another concurrent update.
With snapshot isolation enabled there is a chance that a commit will fail and that an error will be raised. This is a good thing.
In the code shown above if SwapCards throws an error the client code catches the error, prints a message and continues. Perhaps instead the client code should retry the swap?
Concurrency exceptions (that the client code needs to handle)
$ dotnet run
The code below calls the SwapCards stored procedure 1000 times using C#.
Program.cs
$ node index.js
The code below calls the SwapCards stored procedure 1000 times using JavaScript and the 'mssql' node module.
index.js
$ javac Program.java
then
$ java -cp ".:/Users/neilhaddley/sqljdbc_9.2/enu/mssql-jdbc-9.2.1.jre11.jar" Program
or
$ export CLASSPATH=.:/Users/neilhaddley/sqljdbc_9.2/enu/mssql-jdbc-9.2.1.jre11.jar
$ java Program
The code below calls the SwapCards stored procedure 1000 times using Java.
Program.java
Full T-SQL code