【问题标题】:Transaction within transaction交易中的交易
【发布时间】:2011-01-21 04:07:33
【问题描述】:

我想知道在另一个内部进行交易是否安全且受鼓励?

我有一个方法:

def foo():
    session.begin
    try:
          stuffs
    except Exception, e:
         session.rollback()
         raise e
    session.commit()

以及在事务中调用第一个方法:

def bar():
    stuffs
    try:
         foo()   #<<<< there it is :)
         stuffs
    except Exception, e:
        session.rollback()
        raise e
    session.commit()

如果我在 foo 方法上遇到异常,所有操作都将是 回滚?其他一切都会正常工作吗? 谢谢!!

【问题讨论】:

  • 嵌套事务(例如 Oracle 的 AUTONOMOUS_TRANSACTION)有资格作为反模式,除了以下两种情况:审计(因此即使语句回滚,尝试也会被审计)和错误日志记录(捕获何时/何地存在故障)。所有其他情况都应使用保存点。哎呀,事务范围不属于在任何函数或过程中处理;提交或回滚应该是最终调用者的责任。

标签: python database postgresql sqlalchemy


【解决方案1】:

在 SQLAlchemy 中有两种嵌套事务的方法。一种是虚拟事务,其中 SQLAlchemy 跟踪您已发出多少个开始,并且仅在最外层事务提交时才发出提交。然而,回滚会立即发出。因为事务是虚拟的 - 即数据库对嵌套一无所知,所以在回滚后您不能对该会话执行任何操作,直到您也回滚所有外部事务。要允许使用虚拟事务,请将 subtransactions=True 参数添加到 begin() 调用。存在此功能是为了允许您在可能相互调用的函数内部使用事务控制,而无需跟踪您是否在事务中。为了使其有意义,请使用autocommit=True 配置会话,并始终在事务函数中发出session.begin(subtransactions=True)。

嵌套事务的另一种方法是使用真正的嵌套事务。它们是使用保存点实现的。如果回滚嵌套事务,则该事务中所做的所有更改都将回滚,但外部事务仍然可用,并且外部事务所做的任何更改仍然存在。使用嵌套事务问题session.begin(nested=True) 或只是session.begin_nested()。并非所有数据库都支持嵌套事务。 SQLAlchemy 的测试套件库配置函数sqlalchemy.test.requires.savepoints 是这么说的:

    emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'),
    no_support('access', 'not supported by database'),
    no_support('sqlite', 'not supported by database'),
    no_support('sybase', 'FIXME: guessing, needs confirmation'),
    exclude('mysql', '<', (5, 0, 3), 'not supported by database')

在 PostgreSQL SQLAlchemy 上,嵌套事务工作得很好。

【讨论】:

    【解决方案2】:

    你不能,PostgreSQL 不支持子事务。你可能想使用保存点,但那是别的东西。

    【讨论】:

    • 好的。但我执行上面的代码,sqlalchemy 允许我这样做。幕后发生了什么?
    • 我从来没有使用过 SQLAlchemy 的经​​验,无法帮助你。但我知道 PostgreSQL 不能做子事务,Oracle 是少数几个能做到这一点的数据库之一。请参阅手册sqlalchemy.org/docs/session.html#managing-transactions sqlalchemy 如何处理事务和保存点。测试,测试,测试!当你的 ORM 看起来允许你做你的数据库不能做的事情时,不要相信它......
    【解决方案3】:

    在 PostgreSQL 上嵌套事务工作得很好。

    嗯,你不会得到错误(只是警告),这是真的。但是不能提交内部事务并回滚外部事务,外部事务也会回滚内部事务。

    开始;

    插入 x(foo) 值('John');

    开始; -- 警告!

    INSERT INTO y(bar) VALUES('Jane');

    提交; -- 提交内部事务

    回滚; -- 将回滚两个插入,而不仅仅是第一个,表“x”中的那个

    据我所知,Oracle 是少数拥有此选项的公司之一。

    【讨论】:

    • 不是嵌套的 postgresql 事务。 SQLAlchemy 嵌套事务。内部事务导致 SAVEPOINT 和 RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT 对。这会导致人们期望从嵌套事务中获得的行为。它实际上也是在 Oracle 后端使用 SAVEPOINT 实现的。我相应地澄清了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    相关资源
    最近更新 更多