All the books I've seen so far, talking about transactions show scenarios with several SQL statements involved.
But what's about single statements? What level of isolation do they have? Is it specified somewhere in a standard? Or does it depend on RDBMS and isolation level?
Let me show a couple of examples.
-
UPDATE table SET value = value + 1 WHERE id = 1;
This is a composite
read-update-write
operation. Can a parallel transaction change the value betweenread
andwrite
operations? Some book states that this operation is atomic (in multithreaded programming meaning) in the most of the RDBMS. -
SELECT * FROM table t1 JOIN table t2 USING (id);
If the table is quite large (or query would have some complicated filtering clause), is it possible at some isolation level that
t1.*
andt2.*
columns would differ due to parallel update? -
SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2);
Is it possible that some records from
table1
are removed after sub-select has been executed? (Here I assume thattable2.t_id
referencestable1.id
with cascaded removal.) -
CTE…
Links to the useful manuals that fully explain all the details of transactions are also appreciated.
Best Answer
For SQL Server:
In SQL Server, there is 4 transaction isolation levels (in pessimistic locking model). Default transaction isolation level is
Read Committed
, and locks are placed on a statement level. If you have a transaction that has 2 statements inside it that retrieve same data, and in the middle of that transaction (right after 1st statement but before 2nd statement started) some other transaction modifies the data that is retrieved by first transaction, then first transaction will return different data in 1st and 2nd statements.That is known as non-repeatable read problem. This can be solved by increasing transaction isolation level to
REPEATABLE READ
where locking happens on transaction level (not on a statement level)UPDATE table SET value = value + 1 WHERE id = 1;
No it can't. This is a single statement, and during it Exclusive lock is placed on rows that are being modified.
No other transactions or statements can modify these rows until our update statement is complete
SELECT * FROM table t1 JOIN table t2 USING (id);
Yes, in
READ UNCOMMITED
is possible (or when with (NOLOCK) hint is specified), since Shared lock is not applied. In other isolation levels - no, because Shared lock is being placed on rows from t1 and t2, and during it rows can't be modified (Exclusive lock can't be acquired by other transactions)SELECT * FROM table1 WHERE id IN (SELECT t_id FROM table2)
In
READ UNCOMMITTED
is possible. In higher isolation levels - not possible, because during execution of this statement, Shared lock is placed on all selected rows of table1 and table2, and no other transaction is able to modify the rows of table1 and table2 (put Exclusive lock) until our select statement completes and Shared lock released from table1 and table2Here you can read more information about SQL Server's isolation levels: https://docs.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver15