根据文档,我们应该对对象使用以下模式sessionmaker:
Session = sessionmaker(engine)
with Session.begin() as session:
session.add(some_object)
Run Code Online (Sandbox Code Playgroud)
在多线程环境中,我们也应该使用单线程scoped_session并共享它。因此,在我的程序中__init__.py,我创建了一个并将其导入到程序中的其他位置:
engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
Session = scoped_session(sessionmaker(bind=engine))
Run Code Online (Sandbox Code Playgroud)
问题是,我应该如何结合这两种方法?这似乎是建议的方式,但它出错了:
from myapp import Session
with Session.begin() as session:
query_result = session.query(MyModel).all()
----
Exception has occurred: AttributeError
'SessionTransaction' object has no attribute 'query'
Run Code Online (Sandbox Code Playgroud)
我尝试了以下方法并且它有效,但它似乎不遵循文档,而且我担心它会破坏一些不明显的东西。谁能确认这是否正确?
from myapp import Session
with Session() as session, session.begin():
query_result = session.query(MyModel).all()
Run Code Online (Sandbox Code Playgroud)
我一直在查看其他回复,但几乎没有看到解决具体问题的答案。
该
Session对象具有自动开始行为,因此通常不需要Session.begin()显式调用该方法。然而,它可以用于控制事务状态何时开始的范围。
您可以使用Session.begin()(1.4 中的新增功能)获取SessionTransaction可用作上下文管理器的实例,该实例将在成功退出时自动提交。
根据您的错误,立即调用scoped_session返回 a SessionTransaction,因此您无需再次开始。
总而言之,您绝对可以使用堆叠上下文管理器,但它没有必要,因此您不妨坚持使用原始流程:
Session = scoped_session(...)
with Session() as session: # NB. session is a thread local SessionTransaction
...
session.commit()
Run Code Online (Sandbox Code Playgroud)
或代理的Session
Session = scoped_session(...)
@on_request_end
def remove_session(req):
Session.remove()
@route("/xyz", ...)
def handle_xyz():
instance = Class(...)
Session.add(instance)
Session.commit()
Run Code Online (Sandbox Code Playgroud)