在由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或DO调用中也能进行事务控制。例如,如果调用栈是CALL proc1() → CALL proc2() → CALL proc3(),那么第二个和第三个过程可以执行事务控制动作。但是如果调用栈是CALL proc1() → SELECT func2() → CALL proc3(),则最后一个过程不能做事务控制,因为中间有SELECT。
PL/pgSQL 不支持保存点(SAVEPOINT/ROLLBACK TO SAVEPOINT/RELEASE SAVEPOINT)。保存点的典型用法可以用带异常处理器的代码块替代(见Section 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)驱动的游标循环中,不允许使用事务命令。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。