【问题标题】:How to handle multiple requests without SQLAlchemy crashing/raising exceptions?如何在没有 SQLAlchemy 崩溃/引发异常的情况下处理多个请求?
【发布时间】:2013-11-07 05:33:14
【问题描述】:

上下文:我正在开发一个 Flask 应用,在 CherryPy 上运行,DB 使用 SQLAlchemy ORM 处理。

问题:

该应用程序运行良好并且可以执行我想要的所有操作,但是,如果我有一个从 DB 获取一些数据并显示的页面,并且我按住“Ctrl + R”或“F5”。也就是说,不断刷新页面,发出那么多数据库请求。前几个很好,然后就坏了。 记录以下错误:

(OperationalError) (2013, 'Lost connection to MySQL server during query')

Can't reconnect until invalid transaction is rolled back (original cause: 
InvalidRequestError: Can't reconnect until invalid transaction is rolled back)

This result object does not return rows. It has been closed automatically.

(ProgrammingError) (2014, "Commands out of sync; you can't run this command now")

还有另一个困扰我的错误(但这次没有记录),它是

dictionary changed size during iteration

当我使用获得的值来填充字典迭代查询时会发生这种情况。字典是函数的本地(字典的范围)。

更多信息:

我如何处理会话:

当您进入任何页面时会创建一个新会话,使用该会话执行所有数据库事务,并且在呈现 HTML 之前关闭会话。从技术上讲,这意味着会话的范围与 HTTP 请求相同。

只有在updating 表或inserting 进入表期间引发异常时,我才会执行session.rollback()。在任何 query() 操作期间没有 rollback()。 我很确定我犯了一些愚蠢的错误,或者没有以正确的方式做事。

像这样的无限刷新并不是一个可能的情况,但不能忽视。 另外,我认为当有很多用户同时使用它时,行为会相似。

SQLAlchemy 引擎 sessionmaker 的处理方式

sql_alchemy_engine = create_engine(self.db_string, echo=False, encoding="utf8", convert_unicode=True, pool_recycle=9)
sqla_session = sessionmaker(bind=sql_alchemy_engine)

按照 SQLA 文档中的建议,它只执行一次,并在需要时创建并返回 sqla_session() 的新会话。

【问题讨论】:

    标签: python python-2.7 sqlalchemy flask-sqlalchemy


    【解决方案1】:

    如果您使用 Flask,则应该使用 flask-sqlalchemy,并让 Flask 请求上下文管理您的会话,而不是手动处理您的引擎和会话。这就是 SQLAlchemy 推荐的方式:

    大多数 Web 框架都包含用于建立与请求相关联的单个 Session 的基础架构,该 Session 在请求结束时被正确构建和拆除,相应地拆除。此类基础设施部分包括 Flask-SQLAlchemy 等产品,用于与 Flask Web 框架结合使用,以及 Zope-SQLAlchemy,用于与 Pyramid 和 Zope 框架结合使用。 SQLAlchemy 强烈建议尽可能使用这些产品。

    http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html?highlight=flask

    然后您只需通过以下方式创建引擎:

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'your db uri'
    
    db = SQLAlchemy(app)
    

    或者,如果您使用的是应用工厂:

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    def create_app():
        app = Flask(__name__)
        app.config['SQLALCHEMY_DATABASE_URI'] = 'your db uri'
    
        db.init_app(app)
    

    这样,您应该使用的基本声明模型将位于db.Model,而您应该使用的会话将位于db.session

    【讨论】:

      猜你喜欢
      • 2021-12-26
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      • 2019-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-03
      相关资源
      最近更新 更多