从 PendingRollbackError 中恢复并允许后续查询
Posted
技术标签:
【中文标题】从 PendingRollbackError 中恢复并允许后续查询【英文标题】:Recover from PendingRollbackError and allow subsequent queries 【发布时间】:2021-11-27 15:10:31 【问题描述】: 我们有一个pyramid
网络应用程序。
我们在 Zope 交易中使用 SQLAlchemy@1.4
。
在我们的应用程序中,在刷新as described here 期间可能会发生错误,这会导致任何后续使用 SQLAlchemy 会话抛出PendingRollbackError
。刷新期间发生的错误是无意的(错误),并被引发到我们的异常处理视图......它尝试使用来自 SQLAlchemy 会话的数据,然后抛出 PendingRollbackError
。
如果您没有正确构建事务管理,是否可以从PendingRollbackError
“恢复”? SQLAclhemy 文档说要避免这种情况,您基本上“只需要以正确的方式做事”。不幸的是,这是一个庞大的代码库,开发人员并不总是遵循正确的事务管理。如果使用保存点/嵌套事务,这个问题也很复杂。
def some_view():
# constraint violation
session.add_all([Foo(id=1), Foo(id=1)])
session.commit() # Error is raised during flush
return 'data': 'some data'
def exception_handling_view(): # Wired in via pyramid framework, error ^ enters here.
session.query(... does a query to get some data) # This throws a `PendingRollbackError`
我想知道我们是否可以做类似下面的事情,但不了解pyramid
+ SQLAlchemy
+ Zope 事务足以了解其含义(考虑嵌套事务等的可能性时)。
def exception_handling_view(): # Wired in via pyramid framework, error ^ enters here.
def _query():
session.query(... does a query to get some data)
try:
_query()
except PendingRollbackError:
session.rollback()
_query()
【问题讨论】:
是否应该PendingRollbackError
导致 HTTP 请求重试几次,直到永久失败?
@aaron 问题在于它是一个遗留代码库,事务和保存点的使用并不一致——而且新开发人员不知道如何使用它们。此外,异常没有得到正确处理,因此未处理的异常可能导致嵌套事务绕过回滚(如果未使用上下文管理器)。
【参考方案1】:
与其尝试执行查询,不如尝试获取连接:
def exception_handling_view():
try:
_ = session.connection()
except PendingRollbackError:
session.rollback()
session.query(...)
session.rollback()
只回滚最里面的事务,正如通常预期的那样——假设嵌套事务是通过显式 session.begin_nested()
有意使用的。
您不必回滚父事务,但如果您决定这样做,您可以:
while session.registry().in_transaction():
session.rollback()
【讨论】:
以上是关于从 PendingRollbackError 中恢复并允许后续查询的主要内容,如果未能解决你的问题,请参考以下文章