我的情况是我必须将一部分代码作为自己的交易提交
我创建了一个表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;
表中的值未填充
我希望1
或2
应添加到表格subtransaction_tbl
,但令我惊讶的是没有插入任何值。我想象一个新的子事务由函数打开,它不应该依赖于父事务。如果我是对的,请告诉我。
Postgres是否有自主交易?或者我是否必须修改我的plpython3u函数?
答案 0 :(得分:19)
Postgres确实支持嵌套事务,但它们与传统SQL不同,更像是具有嵌套部分点的事务。
在顶层,您始终拥有典型的BEGIN/COMMIT/ROLLBACK
,在嵌套级别上,您必须使用以下命令:
SAVEPOINT name
- 创建一个新的保存点,其名称对事务而言是唯一的RELEASE SAVEPOINT name
- 提交保存点,但只有在包含的事务提交时才会保留ROLLBACK TO SAVEPOINT name
- 回滚保存点您还必须确保:
SAVEPOINT
使用的名称都是唯一的; SAVEPOINT
中的失败会向上传播到顶层。最后一点有点棘手,除非您使用可以自动为您执行此操作的库。
当我写pg-promise时,我确保这两项规定得到保证:
level_1
,level_2
等等; ROLLBACK TO SAVEPOINT name
和顶级ROLLBACK
- 所有内容都构建在标准的promise-chaining逻辑上。另请参阅解释的PostgreSQL嵌套事务的limitations ...
答案 1 :(得分:17)
Postgres中有没有自主交易,包括Postgres 9.4。在该功能中完成的所有操作都将与事务一起回滚。
项目列表中有一个打开的TODO项目:
以下是该功能的讨论:
目前,解决方法可能是(ab-)使用dblink:
还有SAVEPOINT
的相关概念。 (不一样!):
plpython有子交易(with plpy.subtransaction():
),但这与自治交易不同。没有单独的COMMIT
。它所做的只是将几个语句捆绑在一起,使它们成为原子。如果没有它,如果异常发生在中间某处,并且您捕获该异常,则只会执行此异常的代码。如果你把它包装成一个子交易,它全部或全部。这就像使用SAVEPOINT
,而不是自治事务。 Per documentation:
子事务上下文管理器不会捕获错误,只是它 确保在其范围内执行的所有数据库操作都是 原子承诺或回滚。