As 2 sessões devem ficar assim:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
e
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 funcionar corretamente, todos transações envolvidas que pretendem atualizar a linha precisam usá-la. No seu exemplo, a sessão 2 não está usando
with_for_update
. Como você não disse para usar FOR UPDATE
, é livre para ler o valor antigo da linha (já que o novo valor ainda não foi confirmado e os bloqueios não bloqueiam leitores puros), modifique-o nesse valor na memória e escreva-o de volta. Se você não quiser usar
FOR UPDATE
em todos os lugares em que você lê a linha com a intenção de alterá-la, você pode usar isolation level serializable
em todos os lugares. No entanto, se você fizer isso, as coisas podem não bloquear, mas parecerão bem-sucedidas até a confirmação e, em seguida, lançarão erros de serialização que precisarão ser capturados e tratados. Observação: Seu exemplo de pré-edição deve ter funcionado, pois ambas as sessões foram rotuladas com
with_for_update
.