I use a small transaction consisting of two simple queries: select and update:
SELECT * FROM XYZ WHERE ABC = DEF
and
UPDATE XYZ SET ABC = 123 WHERE ABC = DEF
Often a situation arises when a transaction is started by two threads, and depending on the level of isolation level lock (RepeatableRead, Serialization). Both transactions try to read and update the exact same line. I wonder why this is happening. What is the order of queries leading to a deadlock? I read a little about the lock (general, exclusive) and how long the locks remain for each isolation level, but I still do not quite understand ...
I even prepared a simple test that always leads to a deadlock. I looked at the test results in SSMS and SQL Server Profiler. I started the first request, and then immediately the second.
First request:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION SELECT ... WAITFOR DELAY '00:00:04' UPDATE ... COMMIT
Second request:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION SELECT ... UPDATE ... COMMIT
Now I canโt show you detailed logs, but it looks less or more similar (I most likely missed Lock: deadlock, etc. somewhere):
(1) SQL:BatchStarting: First query (2) SQL:BatchStarting: Second query (3) Lock:timeout for second query (4) Lock:timeout for first query (5) Deadlock graph
If I understand the locks well, in (1) the first request takes a general lock (for SELECT), then goes into sleep mode and saves the general lock until the end of the transaction. In (2), the second query also accepts a general lock (SELECT), but cannot accept an exclusive lock (UPDATE), while the same line has general locks, which leads to a lock: timeout. But I canโt explain why the second timeout for the second request occurs. I guess I donโt understand the whole process very well. Can anyone give a good explanation?
I did not notice deadlocks using ReadCommitted, but I'm afraid they might happen. Which solution do you recommend?