在由 CALL 命令调用的过程以及匿名代码块(DO 命令)中,可以使用 COMMIT 和 ROLLBACK 命令来结束事务。在使用这些命令结束事务后,会自动启动新的事务,因此没有单独的 START TRANSACTION 命令。(请注意,BEGIN 和 END 在 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 CHAIN 和 ROLLBACK AND CHAIN 命令可以完成此操作。
只有在顶层或嵌套的 CALL 或 DO 调用中,并且没有任何其他中间命令的情况下,才有可能进行事务控制。例如,如果调用堆栈为 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();
通常,游标在事务提交时自动关闭。但是,像这样在循环中创建的游标会在第一次 COMMIT 或 ROLLBACK 时自动转换为可保持的游标。这意味着游标在第一次 COMMIT 或 ROLLBACK 时会被完全评估,而不是逐行评估。游标在循环之后仍然会自动删除,因此这对于用户来说大多是不可见的。但是,必须记住,游标查询所获取的任何表或行锁在第一次 COMMIT 或 ROLLBACK 后将不再持有。
不允许在由非只读命令驱动的游标循环中使用事务命令(例如 UPDATE ... RETURNING)。
如果您发现文档中有任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。