Repeatable Read
This level is not as strict as
serializable, and it does not take out range locks. However, this means
that data can be inserted into a set in such a way that the phantom
reads scenario can occur.
Shared (S) locks are taken out and not released
until the end of the transaction, including intent shared locks going
up the lock hierarchy. These can be easily demonstrated by running the
same block of code shown for the serializable example, but using SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; instead of the first line. The results do not show range locks, but standard full locks instead (see Figure 3).
Read Committed
Read committed is the default locking
behavior of SQL Server 2012. In this environment, shared locks are
released after the particular read operation, but, as in the more
pessimistic isolation levels, they are still blocked by exclusive
locks. This isolation level can exhibit some of the concurrency issues
that were described earlier; but with fewer locks being taken out, the
behavior is often considered good enough for many environments. It is
entirely possible to read a piece of data in the transaction and then
read it again later in the transaction, only to find that another
transaction has snuck in and removed or changed that data — a
non-repeatable read, which as implied, is not possible in the
repeatable read isolation level.
If SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
is substituted in the preceding example, then both the shared locks
from the repeatable read isolation level and the range locks of the
serializable level will be eliminated, leaving only the shared lock on
the whole database. See Figure 4.
Read Uncommitted/NOLOCK
We mention the NOLOCK
hint here because that is how many developers force the read
uncommitted isolation level on their system. It is the least
pessimistic isolation level, but it still is not classed as optimistic.
In the read uncommitted isolation level, shared
(S) locks are not taken out at all. This also applies if the
transaction is using a different isolation level but the NOLOCK
hint is used. The upshot of this is the problem of dirty reads
described earlier. Read transactions are not blocked by data with
exclusive locks, but the data they read is of a potentially dubious
value. Performance is increased, as without shared locks being
acquired, there is no lock compatibility to be checked.
Note that some locks can still block reads in
this isolation level — locks that stop anything getting near data, such
as schema modification locks. The behavior of this isolation level has
already been demonstrated as part of the dirty reads problem, so that
code is not repeated here.
Snapshot
The optimistic snapshot isolation level is turned on using the command SET TRANSACTION ISOLATION LEVEL SNAPSHOT;. Before this can be done, however, the database must be configured to allow it, as shown here:
ALTER DATABASE AdventureWorks
SET ALLOW_SNAPSHOT_ISOLATION ON;
After the snapshot isolation level is
set, the database can perform the extra work required when a
transaction starts, ensuring that for the length of that transaction,
the entire database appears as it did at the start of it. This has an
interesting effect on the locking required for reads — no locks are
required.
This may sound useful, but every time data is
changed, the previous copy of the data must be stored until every
transaction that was active when the change was made has been completed
(except its own transaction, which naturally sees the newer copy of the
data). The data to support this behavior is kept in the tempdb database.
Read Committed Snapshot
This isolation level is similar to the
snapshot isolation level, but it only provides statement-level read
consistency. Therefore, the behavior feels more like the read committed
isolation level, with the same drawbacks of read committed regarding
non-repeatable reads and the like, but it doesn’t have the same
blocking problems as read committed. When another transaction requests
locked data using this isolation level, row versioning can provide a
copy of it. However, the older versions of these rows are released when
the transaction is over, thereby allowing more side-effects than are
possible in the snapshot isolation level.
This last isolation level cannot be set using the SET TRANSACTION ISOLATION LEVEL command; it can only be set using the following:
ALTER DATABASE AdventureWorks
SET READ_COMMITTED_SNAPSHOT ON;