Tyto 2 relace by měly vypadat takto:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
a
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
Aby FOR UPDATE
správně fungovat, vše příslušné transakce, které mají v úmyslu řádek aktualizovat, jej musí použít.
Ve vašem příkladu relace 2 nepoužívá with_for_update
. Protože jste mu neřekli, aby použil FOR UPDATE
, je zdarma načíst starou hodnotu řádku (protože nová hodnota ještě nebyla potvrzena a zámky neblokují čisté čtečky), poté ji upravit na hodnotu v paměti a poté ji zapsat zpět.
Pokud nechcete použít FOR UPDATE
všude, kde čtete řádek s úmyslem jej změnit, můžete místo toho použít isolation level serializable
všude. Pokud to však uděláte, věci se nemusí zablokovat, ale spíše se budou zdát úspěšné až do odevzdání, pak vyvolá chyby serializace, které bude třeba zachytit a řešit.
Poznámka: Váš příklad předúpravy by měl fungovat, protože obě relace byly označeny with_for_update
.