多线程 sqlalchemy Web 应用中建议的scoped_session使用模式是什么?



我正在用python和sqlalchemy-0.7编写一个应用程序。它首先初始化 sqlalchemy orm(使用声明式),然后启动多线程 Web 服务器 - 我目前正在使用 web.py 进行快速原型设计,但将来可能会改变。我还将为计划作业等添加其他"线程",可能使用其他 python 线程。

从 SA 文档中,我知道我必须使用 scoped_session() 来获取线程本地会话,所以我的 web.py 应用程序最终应该看起来像这样:

import web
from myapp.model import Session  # scoped_session(sessionmaker(bind=engine))
from myapp.model import This, That, AndSoOn
urls = blah...
app  = web.application(urls, globals())
class index:
    def GET(self):
        s = Session()
        # get stuff done
        Session().remove()
        return(stuff)
class foo:
    def GET(self):
        s = Session()
        # get stuff done
        Session().remove()
        return(stuff)

这是处理会话的正确方法吗?

据我了解,我应该在每个方法上都得到一个scoped_session,因为它会给我一个我事先无法获得的线程本地会话(比如在模块级别)。

另外,我应该在每个方法结束时调用 .remove() 或 .commit() 或类似的东西,否则会话仍将包含持久对象,我将无法查询/访问其他线程中的相同对象?

如果这种模式是正确的,那么可能通过只写一次来做得更好,也许使用装饰器?这样的装饰器可以获取会话,调用该方法,然后确保正确释放会话。如何将会话传递给装饰函数?

是的,这是正确的方法。

例:

带有 Flask-sqlalchemy 扩展的 Flask 微框架可以执行您所描述的操作。它还在每个 HTTP 请求("view"函数)结束时自动执行 .remove(),因此会话由当前线程释放。仅调用 .commit() 是不够的,您应该使用 .remove()。

不使用 Flask 视图时,我通常使用"with"语句:

@contextmanager
def get_db_session():
    try:
        yield session
    finally:
        session.remove()
with get_db_session() as session:
    # do something with session

您可以创建类似的装饰器。

作用域会话创建 DBMS 连接池,因此此方法将比在每个 HTTP 请求处打开/关闭会话更快。它也适用于绿绿(gevent或eventlet)。

如果为每个请求创建新会话,并且每个请求都由单个线程处理,则无需创建作用域会话。

您必须调用s.commit()以使挂起的对象持久化,即将更改保存到数据库中。

您可能还希望通过调用 s.close() 来关闭会话。

相关内容

  • 没有找到相关文章

最新更新