I'm running Postgres12 and confused about the behavior of the serializable transaction level.
Tables:
Events
- id
- difficulty
Managers
- id
- level
Intended behavior (within serialized transaction):
- check if there are 7 or more events of difficulty=2
- if so, insert a manager with level=2
I'm running the following transactions in serializable but not seeing the behavior I am expected (expected the serializable transaction to detect write skew between 2 sessions)
-- session 1:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT count(*) from events WHERE difficulty=2
-- RETURNS 7
-- now start session 2
-- session 2:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT id FROM events WHERE difficulty=2 LIMIT 1;
/*
id
----
4
*/
UPDATE events SET difficulty=1 WHERE id=4;
COMMIT;
now there are only 6 events of difficulty=2
-- back in session 1
-- since we have counted 7 events of difficulty=2 in this session, create a manager
INSERT INTO manager (level) VALUES (2);
COMMIT;
-- Expected write skew to be detected here bc the read event rows have seen updates (only 6 actually)
Unfortunately, our final state is now 6 events of difficulty=2 and a manager of level 2. Why didn't serializable isolation prevent this write skew? What am I misunderstanding about serializable isolation use case? Why are events with difficulty=2 not locked or watched by predicate locking or some isolation mechanism?