相关文章推荐
酷酷的茴香  ·  android android11 ...·  3 周前    · 
长情的火锅  ·  Android 开发 ...·  1 年前    · 
失望的作业本  ·  node.js - node-mysql ...·  1 年前    · 

如何让Flask-SQLAlchemy在出现异常时自动回滚会话?

27 人关注

我想设置一个用 Flask-SQLAlchemy 构建的应用程序,如果视图引发了一个在视图代码外冒泡的异常(即没有在内部被捕获),则回滚所有对数据库所做的更改。

我希望它能够工作,即使一些对象在子交易中被刷入数据库,无论是自动还是直接通过 session.commit()

类似于 Django的交易请求包装 .

2 个评论
你的意思是,像在芹菜任务或什么?
不,是在Flask应用里面。我希望在响应请求的过程中,如果视图代码中出现未捕获的异常,事务会自动回滚。
python
flask
transactions
flask-sqlalchemy
dukebody
dukebody
发布于 2015-10-22
3 个回答
reptilicus
reptilicus
发布于 2021-08-24
已采纳
0 人赞同

你可以做这样的事情。

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

看一看here来获取拆解_请求信息。如果你是在调试模式下,你可能需要设置PRESERVE_CONTEXT_ON_EXCEPTION的配置变量。

我已经将上述配置设置为 "真"。但它仍然无法回滚。
不这样做的原因是什么?
Flask-SQLALchemy有一个选项 SQLALCHEMY_COMMIT_ON_TEARDOWN 。参考文献。 github.com/mitsuhiko/flask-sqlalchemy/blob/... 虽然我一直建议你应该在teardown_request上提交
在v2.4.3版本中, SQLALCHEMY_COMMIT_ON_TEARDOWN 设置已被废弃。见 github.com/pallets/flask-sqlalchemy/issues/216
自动这样做是个好主意吗?如果是,为什么不是默认的呢?为什么/什么时候你想不回滚?
dduffy
dduffy
发布于 2021-08-24
0 人赞同

你可以在一个自定义的错误处理程序中包含回滚功能...

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

See here在自定义错误页面部分。

这个方法对我来说比公认的答案更稳定。在例外情况下,所接受的解决方案似乎并没有真正删除会话,这导致了后续传入请求的失败,并阻塞了网络服务器。
ibz
事实上,公认的解决方案似乎是在做别的事情--在应用拆解时回滚,而不是在例外情况下回滚!这就是所谓的 "回滚"。
它缺少会话删除( db.session.remove() ),正如在@reptilicus的答案中看到的那样。 stackoverflow.com/a/33284980/2340939
@用户2340939 我看了一下 docs.sqlalchemy.org/en/13/orm/contextual.html 而且看来 db.session.remove() 也会 rollback() 的会议。你是否建议用 remove() 来替换 rollback() ?或者说,用 rollback() close() 会更好吗?
很好的发现。根据文档, close() 只是结束,即忽略,不提交正在进行中的事务,而 remove() 实际上是回滚这样的事务。如果这是真的,那么 remove() 就更好了,因为它更符合DRY。但我怀疑文档中误说了 transactions specifically are rolled back ,因为我认为 remove() close() 一样处理潜在打开的事务。但我不确定!
jsoc
jsoc
发布于 2021-08-24
0 人赞同

对我来说,最可靠的解决方案,灵感来自于 dduffy的回答 如果是这样的话,就需要附加一个错误处理程序,专门捕捉SQLAlchemy的异常,并发出回滚指令。

from sqlalchemy import exc
@app.errorhandler(exc.SQLAlchemyError)