Le 2 sessioni dovrebbero assomigliare a questa:
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()
In ordine per FOR UPDATE
per funzionare correttamente, tutti le transazioni coinvolte che intendono aggiornare la riga devono utilizzarla.
Nel tuo esempio, la sessione 2 non utilizza with_for_update
. Dal momento che non gli hai detto di usare FOR UPDATE
, è libero di leggere il vecchio valore della riga (poiché il nuovo valore non è stato ancora confermato e i blocchi non bloccano i lettori puri), quindi modificarlo quel valore in memoria, quindi riscriverlo.
Se non vuoi usare FOR UPDATE
ovunque tu abbia letto la riga con l'intenzione di cambiarla, potresti invece usare isolation level serializable
ovunque. Tuttavia, se lo fai, le cose potrebbero non bloccarsi, ma sembrerà che abbiano successo fino al commit, quindi generano errori di serializzazione che dovranno essere rilevati e gestiti.
Nota: Il tuo esempio di pre-modifica dovrebbe aver funzionato poiché entrambe le sessioni erano etichettate con with_for_update
.