This document is intended for application developers and database administrators who are willing to get an overview of comm concurrency problems to which transaction isolation levels respond in the particular case of Microsoft SQL Server.
Typographical Conventions Convention Meaning Stylized Consolas Font Used for blocks of code, commands and script examples. Text should be interpreted exactly as presented. Consolas Font Used for inline code, commands or examples. Text should be interpreted exactly as presented. <italic font in brackets> Italic texts set in angle brackets denote a variable requiring substitution for a real value. Italic font Used to denote the title of a book, article, or other publication. Note Additional information or caveats. About screen capture and images Selections and arrows default color is dark red (Red 192, Green 0 and Blue 0) Selections and arrows width is limited to 2 px Selections are rectangles Arrows are used to show relations between important parts of the screen capture Screen captures won’t comprise user desktop or unnecessary white space Highlights on text in an image should be done using yellow color with straight edges. Confidential information should be properly cut off, not blurred. You can simply cut the part of or color it so that it matches the background. ContextIn any relational database system, there is the concept of transaction. A transaction is a set of logical operations that have to be performed in a user session as a single piece of work. Let’s review the properties of a transaction.
Hence, a transaction must be atomic i.e. there is no halfway for it to complete: either all the logical operations occur or none of them occur.
A transaction has to be consistent i.e. any data written using database system must be valid according to defined rules like primary key uniqueness or foreign key constraints.
Once the consistency is ensured, a transaction must be permanently stored to disk. It guarantees the durability required for a transaction.
Last but not least, as multiple transactions could be running concurrently in a database system, we can find transactions that read from or writes to the same data object (row, table, index…). It introduces a set of problems to which different transaction isolation (level) tend to respond. A transaction isolation (level) defines how and when the database system will present changes made by any transaction to other user sessions.
In order to select the appropriate transaction isolation level, having a good understanding on common concurrency problems that can occur is mandatory.
This article is the first one of a series about transaction isolation level. It is divided into two parts. The first one will explain the concurrency problems with a theoretical example while the second will be more practical and we will try to experience these problems on a SQL Server instance.
Concurrency problemsBefore diving into transaction levels details, it’s important to get used to typical concurrency problems and how we call them.
Lost update and dirty writeThis phenomenon happens when two transactions access the same record and both updates this record. The following figure summarizes what could happen in a simple example.
In this example, we have 2 concurrent transactions that access a record with a (60) modifiable value. This record is identified either by its rowId or by a primary key column that won’t be presented here for simplicity.
The first transaction reads this record, does some processing then updates this record and finally commits its work. The second transaction reads the record then updates it immediately and commits. Both transactions do not update this record to the same value. This leads to a loss for the update statement performed by second transaction.

As Transaction 1 overwrites a value that Transaction 2 already modified. We could have said that Transaction 1 did a dirty write if Transaction 2 didn’t commit its work.
Dirty readA dirty read happens when a transaction accesses a data that has been modified by another transaction but this change has not been committed or rolled back yet. Following figure shows a case of dirty read. In this example, record has two columns with a starting value of (60,40). In this context, let’s say we have an applicative constraint that says that the sum of those values must always be 100.

Non-repeatable read or fuzzy read
The situation of non-repeatable read is almost the same as dirty read except that both values are modified. As in previous sub-sections, we will review a graphical representation of a non-repeatable read situation. To do so, we will keep two concurrent transactions accessing two columns of the same record. One of them reads and modifies each value, one at a time, then commits while the other reads the first value, does some processing, reads the second value then commits. Keeping our constraint from previous example (the sum of both values equals 100), the presented situation leads the second transaction to manipulate inconsistent data and maybe to present it to an end-user.

Phantom reads
Phantom reads are a variation of non-repeatable reads in the context of row sets. Here is an example that illustrates this:
Let’s say we have a transaction Transaction 1 that performs twice a SELECT query against a table T , once at its beginning and once just before its end. Let’s assume another transaction Transaction 2 starts after the first one, inserts a new row to the table T and commits before the second time Transaction 1 will run its SELECT query. The result sets that will be returned by the two occurrences of the SELECT query will differ.
Here is a diagram that summarizes the situation:

Locking reads
This is not really a concurrency problem, but more likely a “design pattern”. In short, the principle is to read a value from a given record and update this record based on the returned value inside the same transaction, with the insurance that no other session will modify the value that has just been read.
It’s the concept of SELECT FOR UPDATE in Oracle or SELECT … FROM <table> WITH (UPDLOCK) in SQL Server.
This will only work in SERIALIZABLE isolation level. We won’t discuss it anymore in this article.
Experimentation on SQL ServerThe experimentation scripts presented here are all designed using the AdventureWorks2012 database.
If no precision is made about a transaction isolation level in the experimentation detailed explanation, the results presented are those returned using SQL Server’s default