【问题标题】:How to make Flask-SQLAlchemy automatically rollback the session if an exception is raised?如果引发异常,如何使 Flask-SQLAlchemy 自动回滚会话?
【发布时间】:2016-01-21 22:15:11
【问题描述】:

我想设置一个使用Flask-SQLAlchemy 构建的应用,以在视图引发在视图代码之外冒泡的异常(即未捕获到内部)时回滚对数据库所做的所有更改。

即使某些对象在子事务中自动或直接通过session.commit() 刷新到数据库,我也希望它能够工作。

类似于Django's transaction request wrapping

【问题讨论】:

  • 你是什么意思,比如芹菜任务什么的?
  • 不,在 Flask 应用程序中。如果在响应请求时视图代码中存在未捕获的异常,我希望事务自动回滚。

标签: python flask transactions flask-sqlalchemy


【解决方案1】:

dduffy's answer 启发,对我有用的最可靠的解决方案是附加一个错误处理程序,专门捕获 SQLAlchemy 异常并发出回滚。

from sqlalchemy import exc
@app.errorhandler(exc.SQLAlchemyError)
def handle_db_exceptions(error):
    #log the error: app.logger.error(error)
    db.session.rollback()

@app.teardown_request 钩子方法似乎没有及时修复处于不良状态的 db 连接,然后它被后来的请求从 db 连接池中拉出。 errorhandler 方法在重用之前捕获连接,并将其范围限制为 SQLAlchemy 引发的错误类别,感觉更精确。

【讨论】:

    【解决方案2】:

    您可以在自定义错误处理程序中包含回滚...

    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        return render_template('500.html'), 500
    

    请参阅“自定义错误页面”部分下的 here

    【讨论】:

    • 这种方法对我来说比接受的答案更有效。出现异常时,可接受的解决方案似乎并未真正删除会话,这会导致后续传入请求失败并阻止 Web 服务器。
    • 确实,公认的解决方案似乎在做其他事情 - 回滚应用程序拆除而不是异常!
    【解决方案3】:

    你可以这样做:

    @app.teardown_request
    def teardown_request(exception):
        if exception:
            db.session.rollback()
        db.session.remove()
    

    查看here 以获取 teardown_request 信息。如果您处于调试模式,您可能需要设置 PRESERVE_CONTEXT_ON_EXCEPTION 配置变量。

    【讨论】:

    • 我已经将上面的配置设置为True..但它仍然无法回滚。
    • 不这样做的原因是什么?
    • Flask-SQLALchemy 有一个选项 SQLALCHEMY_COMMIT_ON_TEARDOWN Ref: github.com/mitsuhiko/flask-sqlalchemy/blob/… 虽然我一直建议你应该提交 teardown_request
    • SQLALCHEMY_COMMIT_ON_TEARDOWN 设置已在 v2.4.3 中弃用。见github.com/pallets/flask-sqlalchemy/issues/216
    • 自动执行此操作是个好主意吗?如果是,为什么这不是默认值?为什么/何时不想回滚?
    猜你喜欢
    • 2016-02-24
    • 2023-01-29
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多