De två sessionerna ska se ut så här:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
och
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
För att FOR UPDATE
att fungera korrekt, alla involverade transaktioner som avser att uppdatera raden behöver använda den.
I ditt exempel använder session 2 inte with_for_update
. Eftersom du inte sa åt den att använda FOR UPDATE
, det är gratis att läsa det gamla värdet på raden (eftersom det nya värdet ännu inte har bestämts och lås inte blockerar rena läsare), sedan ändra det i minnesvärdet och sedan skriva tillbaka det.
Om du inte vill använda FOR UPDATE
överallt där du läser rad med avsikt att ändra den, kan du istället använda isolation level serializable
överallt. Men om du gör det kanske saker och ting inte blockerar, utan snarare verkar lyckas tills commit, och sedan kastar serialiseringsfel som måste fångas upp och hanteras.
Obs! Ditt förredigeringsexempel borde ha fungerat eftersom båda sessionerna var märkta med with_for_update
.