在SQLAlchemy Core中使用`with`上下文管理器如何知道事务是否回滚?

时间:2018-06-04 06:54:30

标签: python sqlalchemy

SQLAlchemy CORE doc for transactions建议使用with上下文管理器,如下所示:

# runs a transaction
with engine.begin() as connection:
    r1 = connection.execute(table1.select())
    connection.execute(table1.insert(), col1=7, col2='this is some data')

with connection.begin() as trans:
    r1 = connection.execute(table1.select())
    connection.execute(table1.insert(), col1=7, col2='this is some data')

无论哪种方式,我如何知道交易是否已被执行和提交,或者是否已被回滚?

2 个答案:

答案 0 :(得分:1)

由于在发生异常时执行回滚,如果执行with之后的代码,您可以放心,该事务尚未回滚。

如果您还需要测试,那么您可以使用通常的python结构,例如:

try:
    with connection.begin() as trans:
        r1 = connection.execute(table1.select())
        connection.execute(table1.insert(), col1=7, col2='this is some data')
except:
    # The transaction has been rolled back, you can log or otherwise
    # react to that fact
    ...
    # Finally, propagate the exception to the caller. If you choose not
    # to propagate, then don't use `except:`, but handle a narrower
    # class of exceptions.
    raise

答案 1 :(得分:0)

如果它没有提高,它就会提交。如果您查看文档,您会注意到with语句或多或少等同于:

connection = engine.connect()
trans = connection.begin()
try:
    r1 = connection.execute(table1.select())
    connection.execute(table1.insert(), col1=7, col2='this is some data')
    trans.commit()
except:
    trans.rollback()
    raise

关于注释:with语句不一定是try /的替代,除非您需要异常处理 - 例如当您想知道事务是否回滚时。

如果您必须执行额外的清理或例如在事务回滚时进行日志记录,您仍然需要在try / except中包装with语句,但是您可以确定该事务已被处理在控制之前从由with语句控制的块传递:

try:
    with ...:
        ...

except ...:
    # rolled back

else:
    # committed

您也可以选择重新加载错误,以便其他部分也可以处理清理。当然,例如日志记录也可以由另一个上下文管理器处理:

from contextlib import contextmanager

@contextmanager
def logger(log, error_msg="Oh woe!"):
    try:
        yield

    except:
        log.exception(error_msg)
        raise

...

with logger(log), connection.begin():
    r1 = connection.execute(table1.select())
    connection.execute(table1.insert(), col1=7, col2='this is some data')

在这种情况下,正如您在评论中指出的那样,PEP 343的精神使用with语句消除或隐藏了try / except:

  

这个PEP添加了一个新的声明""使用Python语言可以分解try / finally语句的标准用法。