I am using Flask-SQLAlchemy, with autocommit
set to False
and autoflush
set to True
. It's connecting to a mysql
database.
I have 3 methods like this:
def insert_something():
insert_statement = <something>
db.session.execute(insert_statement);
db.session.commit()
def delete_something():
delete_statement = <something>
db.session.execute(delete_statement);
db.session.commit()
def delete_something_else():
delete_statement = <something>
db.session.execute(delete_statement);
db.session.commit()
Sometimes I want to run these methods individually; no problems there — but sometimes I want to run them together in a nested transaction. I want insert_something
to run first, and delete_something
to run afterwards, and delete_something_else
to run last. If any of those methods fail then I want everything to be rolled back.
I've tried the following:
db.session.begin_nested()
insert_something()
delete_something()
delete_something_else()
db.session.commit()
This doesn't work, though, because insert_something
exits the nested transaction (and releases the savepoint
). Then, when delete_something
runs db.session.commit()
it actually commits the deletion to the database because it is in the outermost transaction.
That final db.session.commit()
in the code block above doesn't do anything..everything is already committed by that point.
Maybe I can do something like this, but it's ugly as hell:
db.session.begin_nested()
db.session.begin_nested()
db.session.begin_nested()
db.session.begin_nested()
insert_something()
delete_something()
delete_something_else()
db.session.commit()
There's gotta be a better way to do it without touching the three methods..
Edit: Now I'm doing it like this:
with db.session.begin_nested():
insert_something()
with db.session.begin_nested():
delete_something()
with db.session.begin_nested():
delete_something_else()
db.session.commit()
Which is better, but still not great.
I'd love to be able to do something like this:
with db.session.begin_nested() as nested:
insert_something()
delete_something()
delete_something_else()
nested.commit() # though I feel like you shouldn't need this in a with block