2025年9月25日: PostgreSQL 18 发布!
支持的版本:当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11

41.8. 事务管理 #

在通过 CALL 命令调用的存储过程以及匿名代码块(DO 命令)中,可以使用 COMMITROLLBACK 命令结束事务。当使用这些命令结束事务后,会自动启动一个新的事务,因此没有单独的 START TRANSACTION 命令。(请注意,BEGINEND 在 PL/pgSQL 中有不同的含义。)

以下是一个简单的例子

CREATE PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
    FOR i IN 0..9 LOOP
        INSERT INTO test1 (a) VALUES (i);
        IF i % 2 = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
    END LOOP;
END;
$$;

CALL transaction_test1();

新事务会以默认的事务特性(如事务隔离级别)开始。在循环提交事务的情况下,可能会希望新事务自动以与前一个事务相同的特性开始。 COMMIT AND CHAINROLLBACK AND CHAIN 命令可以实现这一点。

事务控制仅在顶层调用的 CALLDO 调用中,或者在没有其他中间命令的嵌套 CALLDO 调用中才可能。例如,如果调用栈是 CALL proc1()CALL proc2()CALL proc3(),那么第二个和第三个存储过程可以执行事务控制操作。但是,如果调用栈是 CALL proc1()SELECT func2()CALL proc3(),那么最后一个存储过程不能执行事务控制,因为中间有一个 SELECT

PL/pgSQL 不支持保存点(SAVEPOINT/ROLLBACK TO SAVEPOINT/RELEASE SAVEPOINT 命令)。保存点的典型使用模式可以用带有异常处理器的块来替代(请参阅 第 41.6.8 节)。在底层,带有异常处理器的块会形成一个子事务,这意味着在这样的块内部不能结束事务。

游标循环需要特别考虑。请看这个例子

CREATE PROCEDURE transaction_test2()
LANGUAGE plpgsql
AS $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN SELECT * FROM test2 ORDER BY x LOOP
        INSERT INTO test1 (a) VALUES (r.x);
        COMMIT;
    END LOOP;
END;
$$;

CALL transaction_test2();

通常,游标在事务提交时会自动关闭。然而,像这样在循环中创建的游标会在第一次 COMMITROLLBACK 时自动转换为可保持游标。这意味着游标在第一次 COMMITROLLBACK 时会被完全求值,而不是逐行求值。游标仍然会在循环结束后自动删除,因此这对用户来说基本是不可见的。但必须记住,游标查询所获取的任何表或行的锁将在第一次 COMMITROLLBACK 后不再被持有。

在由非只读命令驱动的游标循环中不允许使用事务命令(例如 UPDATE ... RETURNING)。

提交更正

如果您在文档中发现任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。