Postgres是否支持嵌套或自治事务?

时间:2014-08-21 12:06:01

标签: sql postgresql python-3.x transactions

我的情况是我必须将一部分代码作为自己的交易提交 我创建了一个表subtransaction_tbl

CREATE TABLE subtransaction_tbl
(
  entryval integer
)

语言plpython3u中的函数:

CREATE FUNCTION subtransaction_nested_test_t() RETURNS void
AS $$
plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
with plpy.subtransaction():
    plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
$$ LANGUAGE plpython3u;

第一种情况:

BEGIN TRANSACTION;
INSERT INTO subtransaction_tbl VALUES (4);
select  subtransaction_nested_test_t();
COMMIT TRANSACTION;

表格中的条目是正确的:1,2,4

第二种情况:

BEGIN TRANSACTION;
INSERT INTO subtransaction_tbl VALUES (4);
select  subtransaction_nested_test_t();
ROLLBACK TRANSACTION;

表中的值未填充

我希望12应添加到表格subtransaction_tbl,但令我惊讶的是没有插入任何值。我想象一个新的子事务由函数打开,它不应该依赖于父事务。如果我是对的,请告诉我。

Postgres是否有自主交易?或者我是否必须修改我的plpython3u函数?

2 个答案:

答案 0 :(得分:19)

Postgres确实支持嵌套事务,但它们与传统SQL不同,更像是具有嵌套部分点的事务。

在顶层,您始终拥有典型的BEGIN/COMMIT/ROLLBACK,在嵌套级别上,您必须使用以下命令:

  • SAVEPOINT name - 创建一个新的保存点,其名称对事务而言是唯一的
  • RELEASE SAVEPOINT name - 提交保存点,但只有在包含的事务提交时才会保留
  • ROLLBACK TO SAVEPOINT name - 回滚保存点

您还必须确保:

  • 每个SAVEPOINT使用的名称都是唯一的;
  • 一个SAVEPOINT中的失败会向上传播到顶层。

最后一点有点棘手,除非您使用可以自动为您执行此操作的库。

当我写pg-promise时,我确保这两项规定得到保证:

  • 根据交易级别自动生成保存点名称,level_1level_2等等;
  • 在子事务失败的情况下,它执行包含ROLLBACK TO SAVEPOINT name和顶级ROLLBACK - 所有内容都构建在标准的promise-chaining逻辑上。

另请参阅解释的PostgreSQL嵌套事务的limitations ...

答案 1 :(得分:17)

Postgres中有没有自主交易,包括Postgres 9.4。在该功能中完成的所有操作都将与事务一起回滚。

项目列表中有一个打开的TODO项目:

以下是该功能的讨论:

目前,解决方法可能是(ab-)使用dblink

还有SAVEPOINT的相关概念。 (不一样!):

plpython

plpython有子交易with plpy.subtransaction():),但这与自治交易不同。没有单独的COMMIT。它所做的只是将几个语句捆绑在一起,使它们成为原子。如果没有它,如果异常发生在中间某处,并且您捕获该异常,则只会执行此异常的代码。如果你把它包装成一个子交易,它全部或全部。这就像使用SAVEPOINT,而不是自治事务。 Per documentation

  

子事务上下文管理器不会捕获错误,只是它   确保在其范围内执行的所有数据库操作都是   原子承诺或回滚。