I am working on something similar like here (multithreaded app with sqlalchemy), so I understood, that I should create a new session for each db-query.
I wonder, if using a decorator for each method, which needs DB-access would make sense, or if there are traps using this approach. The decorator is constructed following the last example here .
def dbconnect(func):
def inner(*args, **kwargs):
session = Session() # with all the requirements
try:
func(*args, session=session, **kwargs)
session.commit()
except:
session.rollback()
raise
finally:
session.close()
return inner
@dbconnect
def some_function(some, arguments, session)
session.query(...) # no commit, close, rollback required
some_function("many", "different_arguments")
#session is not required, since provided by decorator
This would make it comparable easy to provide thread-safe DB-access to any function, without the need of implementing the whole try-except-finally-stuff redundant, but I am not sure, if this approach is fail-safe and pythonic, or if there exists another best-practice.
I think it here would make sense to use a scoped_session
, maybe like this:
session_factory = sessionmaker(bind=some_engine)
Session = scoped_session(session_factory)
def dbconnect(func):
def inner(*args, **kwargs):
session = Session() # (this is now a scoped session)
try:
func(*args, **kwargs) # No need to pass session explicitly
session.commit()
except:
session.rollback()
raise
finally:
Session.remove() # NOTE: *remove* rather than *close* here
return inner
@dbconnect
def some_function(some, arguments):
session = Session()
# 'session' is now a handle to the *same* session as in the decorator
session.query(...) # no commit, close, rollback required
some_function("many", "different_arguments")
#session is not required, since provided by decorator
(Warning: Untested)
Decorators that add arguments are interesting but potentially tricky. The argument list as defined is now out of step with what callers will actually use. If you explicitly pass session=something
to this it will raise an exception (though you could check for that in the decorator)
You'll also want to add at least a functools.wraps
(granted, this is short sample code).
Transactions are a good use case for context managers. See What's the recommended scoped_session usage pattern in a multithreaded sqlalchemy webapp? for an idea on that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.