我正在研究像here这样的东西(带有sqlalchemy的多线程应用程序),所以我明白,我应该为每个db-query创建一个新的会话。
我想知道,如果为每个方法使用装饰器,那么需要DB访问才有意义,或者是否存在使用此方法的陷阱。装饰器是在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
这样可以很容易地为任何函数提供线程安全的DB访问,而不需要实现整个try-except-finally-stuff冗余,但我不确定,如果这种方法是故障安全的和pythonic,或者如果存在另一种最佳实践。
答案 0 :(得分:2)
我认为在这里使用scoped_session
是有意义的,也许是这样的:
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
(警告:未经测试)
答案 1 :(得分:1)
添加参数的装饰者很有趣,但可能很棘手。现在定义的参数列表与调用者实际使用的内容不一致。如果你明确地将session=something
传递给它,它将引发异常(尽管你可以在装饰器中检查它)
您还要添加至少一个functools.wraps
(已授予,这是简短的示例代码)。
事务是上下文管理器的一个很好的用例。请参阅What's the recommended scoped_session usage pattern in a multithreaded sqlalchemy webapp?了解相关信息。