Redrock Postgres 搜索 英文
版本: 11 / 12 / 13 / 14 / 15 / 16 / 17

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 调用中,才可能进行事务控制。例如,如果调用堆栈为 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)驱动的光标循环中不允许使用事务命令。