Las 2 sesiones deberían verse así:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
y
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
Para FOR UPDATE
para que funcionen correctamente, todos las transacciones involucradas que tienen la intención de actualizar la fila deben usarla.
En su ejemplo, la sesión 2 no usa with_for_update
. Ya que no le dijiste que usara FOR UPDATE
, es libre de leer el valor anterior de la fila (dado que el nuevo valor aún no se ha confirmado y los bloqueos no bloquean lectores puros), luego modificar ese valor en memoria y luego escribirlo de nuevo.
Si no desea utilizar FOR UPDATE
en todas partes donde lea la fila con la intención de cambiarla, podría usar isolation level serializable
En todas partes. Sin embargo, si lo hace, es posible que las cosas no se bloqueen, sino que parecerán tener éxito hasta la confirmación, y luego generarán errores de serialización que deberán detectarse y solucionarse.
with_for_update
.