3

上下文:我正在开发一个 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 请求相同。

只有在表格或表格session.rollback()中出现异常时,我才会这样做。在任何操作期​​间不。我很确定我犯了一些愚蠢的错误,或者没有以正确的方式做事。updatinginsertingrollback()query()

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

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()在需要时创建并返回一个新会话。

4

1 回答 1

3

如果您使用的是 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)

这样,您应该使用的基本声明性模型将是 atdb.Model并且您应该使用的会话将是 at db.session

于 2013-11-07T14:12:49.420 回答