从 PendingRollbackError 中恢复并允许后续查询

Recover from PendingRollbackError and allow subsequent queries

在我们的应用程序中,刷新 as described here 期间可能会发生错误,这会导致 SQLAlchemy 会话的任何后续使用抛出 PendingRollbackError。刷新期间发生的错误是无意的(一个错误),并被提升到我们的异常处理视图......它试图使用来自 SQLAlchemy 会话的数据,然后抛出 PendingRollbackError.

如果您没有正确构建事务管理,是否可以从 PendingRollbackError 中“恢复”? SQLAclhemy 文档说要避免这种情况,您基本上“只需要以正确的方式做事”。不幸的是,这是一个庞大的代码库,开发人员并不总是遵循正确的事务管理。如果使用 savepoints/nested 个事务,这个问题也很复杂。

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()

与其尝试执行您的查询,不如尝试获取连接:

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()