I have a transaction where
- Transaction start
- I run an update on a row with a given id that is marked currently active and mark it inactive
- Add a new row with a audit_id from the above updated row
- Commit the transaction.
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..
- Transaction begin
- Select id from tableA where x_id = 1 and is_active = true and status = inprogress with (HOLDLOCK)
- Update is_active = false where id = (id from #2)
- Insert into tableA x_id=1, is_active = true, audit_id = (id from #2), status = done
- Commit transaction
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.