多线程sqlalchemy webapp中推荐的作用域会话使用模式是什么?

2024-04-24 23:55:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用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)

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

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

另外,我应该在每个方法结束时调用.remove()或.commit()或something like them,否则会话仍将包含Persistent对象,并且我将无法在其他线程中查询/访问相同的对象?

如果这个模式是正确的,那么只写一次,或者使用一个decorator,可能会使它变得更好?这样的decorator可以获取会话,调用方法,然后确保正确地释放会话。如何将会话传递给修饰函数?


Tags: 方法frompyimportweb应用程序modelsqlalchemy
3条回答

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

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

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

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

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

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

是的,这是正确的方法。

示例:

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

不使用烧瓶视图时,我通常使用“with”语句:

@contextmanager
def get_db_session():
    try:
        yield session
    finally:
        session.remove()

with get_db_session() as session:
    # do something with session

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

作用域会话创建一个DBMS连接池,因此这种方法比在每个HTTP请求时打开/关闭会话更快。它还可以与greenlet(gevent或eventlet)配合使用。

相关问题 更多 >