【问题标题】:scoped_session(sessionmaker()) or plain sessionmaker() in sqlalchemy?sqlalchemy 中的 scoped_session(sessionmaker()) 还是普通的 sessionmaker()?
【发布时间】:2011-09-25 01:28:12
【问题描述】:

我在我的网络项目中使用 SQlAlchemy。我应该使用什么 - scoped_session(sessionmaker()) 或普通的 sessionmaker() - 为什么?还是我应该使用其他东西?

## model.py
from sqlalchemy import *
from sqlalchemy.orm import *

engine = create_engine('mysql://dbUser:dbPassword@dbServer:dbPort/dbName',
pool_recycle=3600, echo=False)
metadata = MetaData(engine)
Session = scoped_session(sessionmaker())
Session.configure(bind=engine)
user = Table('user', metadata, autoload=True)

class User(object):
pass

usermapper = mapper(User, user)

## some other python file called abc.py
from models import *

def getalluser():
   session = Session()  
   session.query(User).all()
   session.flush()
   session.close()

## onemore file defg.py
from models import *

def updateuser():
   session = Session()  
   session.query(User).filter(User.user_id == '4').update({User.user_lname: 'villkoo'})
   session.commit()
   session.flush()
   session.close()

我为每个请求创建一个session = Session() 对象并关闭它。我在做正确的事还是有更好的方法?

【问题讨论】:

    标签: python django orm sqlalchemy flask-sqlalchemy


    【解决方案1】:

    推荐阅读documentation

    提供了scoped_session() 函数,它生成Session 对象的线程管理注册表。它通常用于 Web 应用程序,因此可以使用单个全局变量安全地表示具有对象集的事务会话,并本地化到单个线程。

    简而言之,使用scoped_session() 来保证线程安全。

    【讨论】:

    • 谢谢。为每个请求打开和关闭会话对象是否安全?
    • @northlondoner,不仅安全,而且推荐的做事方式,请参阅sqlalchemy.org/docs/orm/…
    • @DanielKluev,这是一个很长的页面,距离您的评论已经有一段时间了,所以也许我读错了,或者页面已经改变,但似乎页面说的是相反的。对我来说,“不要这样做”代码示例似乎与 OP 代码示例中使用的模式非常相似,其中为每个数据库请求创建一个新会话。这是一个混合术语问题(网页请求与数据库请求)还是我缺少的两个 sn-ps 之间存在一些区别?
    • @mmitchell 目前的文档可能更清晰:Session is not a thread-safe object,而the same article pointed in tuomur answer 仍然存在并且有效,以某种方式解释了它的工作原理,web app explicit example
    【解决方案2】:

    每个方法的Scoped_session都会给你一个你事先无法获得的本地会话线程(比如在模块级别)。不需要在每个方法中打开一个新会话,你可以使用全局会话,创建一个会话仅当全局会话不可用时。也就是说,您可以编写一个返回会话的方法并将其添加到包内的 init.py 中。

    【讨论】:

      【解决方案3】:

      仅供参考,当使用 flask-sqlalchemy 时,提供的会话对象默认是作用域会话对象。

      http://flask-sqlalchemy.pocoo.org/2.3/quickstart/#road-to-enlightenment

      【讨论】:

        【解决方案4】:

        我自己也在研究这个,但我不是专家。

        我的三点是:

        1. SQLAlchemy 文档提供了使用 scoped_session 的建议方法,根据上面 Kluev 先生的评论,在此链接:http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html#using-thread-local-scope-with-web-applications
        2. 在该 Web 位置,SQLAlchemy 文档还说“......强烈建议使用随 Web 框架本身提供的集成工具(如果可用),而不是 scoped_session。”
        3. 例如,Flask-SQLAlchemy 似乎声称它会处理这个问题:http://pythonhosted.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application

        【讨论】:

        • 使用 Flask-SQLAlchemy 的问题是它需要模型的 db.Model 基础根。如果您的模型来自 webapp 以外的其他地方,那么您就不走运了。因此,需要 scoped_session()。
        【解决方案5】:

        不要使用 scoped_session

        不要使用 Flask-SQLAlchemy

        只需在单例/服务类中使用 Session = sessionmaker(),并在每个 http 请求上使用 session = Session() 以保证提供新连接。

        线程本地存储很笨拙,并且涉及保持状态,这与不同的 Web 服务器线程模型不能很好地配合。最好保持无国籍状态。例如,请参阅此处的 SqlAlchemy 文档,如果您使用的是scoped_session,请不要忘记调用.remove()。有人会记得这样做吗?

        以下摘自:https://docs.sqlalchemy.org/en/14/orm/contextual.html#using-thread-local-scope-with-web-applications

        Using the above flow, the process of integrating the Session with the web application has exactly two requirements:
        
        -    Create a single scoped_session registry when the web application first starts, ensuring that this object is accessible by the rest of the application.
        
        -    Ensure that scoped_session.remove() is called when the web request ends, usually by integrating with the web framework’s event system to establish an “on request end” event.
        
        

        【讨论】:

          猜你喜欢
          • 2017-01-11
          • 2012-05-03
          • 1970-01-01
          • 2022-12-17
          • 2013-03-22
          • 1970-01-01
          • 1970-01-01
          • 2022-11-17
          • 2010-11-24
          相关资源
          最近更新 更多