如何在没有SQLAlchemy崩溃/引发异常的情况下处理多个请求?

时间:2013-11-07 05:33:14

标签: python python-2.7 sqlalchemy flask-sqlalchemy

上下文:我正在使用在CherryPy上运行的Flask应用程序,使用SQLAlchemy ORM处理数据库。

问题:

应用程序运行正常并完成我想要的一切,但是,如果我有一个页面从数据库中取出一些数据并显示,我按住“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

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

更多信息:

我如何处理会话:

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

只有在session.rollback()表或updating期间将异常引发到表格中时,才会执行inserting。在任何rollback()操作期间均无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)

它只在ONA中完成,就像在SQLA文档中推荐的那样,并且创建了一个新会话,并在需要时返回sqla_session()

1 个答案:

答案 0 :(得分:3)

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

  

大多数Web框架都包含用于建立与请求相关联的单个会话的基础结构,该会话在请求结束时被正确构造并拆除。这些基础设施包括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)

或者,如果你正在使用app factory:

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