Les 2 sessions devraient ressembler à ceci :
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
et
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
Dans l'ordre de FOR UPDATE
pour fonctionner correctement, tous les transactions impliquées qui ont l'intention de mettre à jour la ligne doivent l'utiliser.
Dans votre exemple, la session 2 n'utilise pas with_for_update
. Puisque vous ne lui avez pas dit d'utiliser FOR UPDATE
, il est libre de lire l'ancienne valeur de la ligne (puisque la nouvelle valeur n'a pas encore été validée et que les verrous ne bloquent pas les lecteurs purs), puis de la modifier avec cette valeur en mémoire, puis de la réécrire.
Si vous ne souhaitez pas utiliser FOR UPDATE
partout où vous lisez la ligne avec l'intention de la changer, vous pouvez utiliser à la place isolation level serializable
partout. Cependant, si vous le faites, les choses ne bloqueront peut-être pas, mais sembleront plutôt réussir jusqu'à la validation, puis généreront des erreurs de sérialisation qui devront être interceptées et traitées.
Remarque : Votre exemple de pré-édition aurait dû fonctionner car les deux sessions étaient étiquetées avec with_for_update
.