I have a transaction where
However, when two concurrent transactions ran, ended up with a scenario where #2 happened twice on the same row and #3 got executed twice resulting in two extra rows being inserted instead of just 1.
TLDR; No two rows should have same audit ids. If transactions ran as intended, row 3 should have never appeared.
id x_id is_active audit_id. status
1. 9 false. null inprogress
2. 9 true 1 done
3. 9 true 1 done
How do I avoid this?
I was looking at ROWLOCKS, UPDATELOCKS and HOLDLOCKs
For the above scenario, looks like I need a HOLDLOCK..
Is the above right? According to what I understand, if I use UPDLOCK, say in another concurrent transaction #2 was already executed, both transactions will end up executing #3, not at once but one after the other in overlapping transactions and I'll end up with two rows having same audit_id and status = done.
With READ COMMITTED SNAPSHOT on you need to opt-in to a lock when reading. Otherwise you'll simply read the "last-known-good" version of the row.
So use UPDLOCK, and add HOLDLOCK if you also need to lock empty ranges (ie where the row doesn't exist and you intend to insert it).
EG
Select id
from tableA with (UPDLOCK,HOLDLOCK)
where x_id = 1
and is_active = true
and status = inprogress