Двете сесии трябва да изглеждат така:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
и
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
За FOR UPDATE
да работи правилно, всички участващите транзакции, които възнамеряват да актуализират реда, трябва да го използват.
Във вашия пример сесия 2 не използва with_for_update
. Тъй като не сте му казали да използва FOR UPDATE
, можете свободно да прочетете старата стойност на реда (тъй като новата стойност все още не е ангажирана и заключванията не блокират чистите четци), след това да я промените тази стойност в паметта, след което да я запишете обратно.
Ако не искате да използвате FOR UPDATE
навсякъде, където четете ред с намерението да го промените, можете вместо това да използвате isolation level serializable
навсякъде. Ако обаче го направите, нещата може да не блокират, а по-скоро ще изглеждат успешни до комита, след което ще изхвърлят грешки при сериализиране, които ще трябва да бъдат уловени и отстранени.
Забележка: Вашият пример за предварително редактиране трябваше да работи, тъй като и двете сесии бяха означени с with_for_update
.