There is a student whose type
attribute is 4 and the minimum value for type
attribute can be 1.
In postgres
In se
The 2 sessions should look like this:
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type = 1
db.session.commit()
and
user = Student.query.with_for_update(of=Student, nowait=True).filter(Student.id == 122).first()
user.type -= 1
db.session.commit()
In order for FOR UPDATE
to work properly, all involved transactions which intend to update the row need to use it.
In your example, session 2 is not using with_for_update
. Since you didn't tell it to use FOR UPDATE
, it is free to read the old value of the row (since the new value has not yet been committed, and locks do not block pure readers), then modify it that in-memory value, then write it back.
If you don't want to use FOR UPDATE
everywhere that you read row with the intention of changing it, you could instead use isolation level serializable
everywhere. However if you do, things might not block, but rather will appear to succeed until the commit, then throw serialization errors that will need to be caught and dealt with.
Note: Your pre-edit example should have worked as both sessions were labelled with with_for_update
.