如果过程在中间失败,那么从 SP 开头开始的更改是否会隐式回滚,或者我们是否必须编写任何显式代码来确保 SP 仅在事务中运行?
CREATE FUNCTION
),它提供了与其他 RDBMS 提供的“存储过程”相同的功能(甚至更多)。
ISO/IEC 标准中定义的CREATE PROCEDURE
) 是在 Postgres 11 中引入的。主要区别(除其他外)是事务处理。参见:
它们中的任何一个总是在事务上下文中运行。 手册:
PostgreSQL 实际上将每条 SQL 语句都视为正在执行 在一笔交易内。如果您不发出
命令,则每个 个别陈述有一个隐含的BEGIN
并且(如果成功)BEGIN
包裹在它周围。COMMIT
...不能
COMMIT
。它们是原子 - 它们成功或失败完全。
嗯,PL/pgSQL 中有错误处理。 说明书:
默认情况下,PL/pgSQL 函数中发生的任何错误都会中止 函数和相关事务的执行。你可以 使用
块捕获错误并从中恢复BEGIN
条款。EXCEPTION
请勿将 PL/pgSQL
BEGIN
(代码块的开始)与 SQL BEGIN
(事务的开始)混淆。
...允许
COMMIT
- 立即启动新事务。 手册中对此有详细说明:
新交易以默认交易特征开始 例如事务隔离级别。如果交易是 在循环中提交,可能需要启动新事务 自动具有与前一个相同的特征。这 命令
和COMMIT AND CHAIN
可以完成此操作。ROLLBACK AND CHAIN
诸如
VACUUM
、CREATE DATABASE
或 CREATE INDEX CONCURRENTLY
之类的命令不在事务上下文中运行,并且在其中也根本不允许。
有些事情永远无法回滚,包括:
如果您使用 Postgres 14 程序,如下所示:
CREATE OR REPLACE PROCEDURE test_error(schema_name text)
LANGUAGE plpgsql
AS
$$
declare
<declare any vars that you need>
BEGIN
<do your thing>
END
$$;
出于所有实际目的,在
BEGIN
和 END
块之间编写的代码在单个事务中执行。因此,如果块中的任何语句失败,则所有先前的语句将自动回滚。您不需要显式编写任何回滚代码。
但是,在某些特殊情况下,人们可以对何时启动/提交/回滚事务进行细粒度控制。请参阅:https://www.postgresql.org/docs/current/plpgsql-transactions.html了解详细信息。
摘自Postgresql官方文档:
在 CALL 命令调用的过程中以及匿名代码中 块(DO命令),可以使用 命令提交和回滚。新的交易开始 使用这些命令结束事务后自动执行,因此 没有单独的 START TRANSACTION 命令。 (请注意 BEGIN 和 END 在 PL/pgSQL 中有不同的含义。)
https://www.postgresql.org/docs/11/plpgsql-transactions.html
过程在事务中运行,因此如果出现错误,事务将回滚。
例如,您创建
my_proc()
程序,将 5
设置为 my.var
那么可能会导致 division by zero
错误,如下所示:
CREATE PROCEDURE my_proc(INOUT value INTEGER) AS $$
BEGIN
SET my.var = 5; -- Here
SELECT 1/value INTO value;
END;
$$ LANGUAGE plpgsql;
首先将
2
设置为my.var
,然后调用my_proc(1)
,则5
成功设置为my.var
,如下所示:
postgres=# SET my.var = 2;
SET
postgres=# CALL my_proc(1);
my_func
---------
1
(1 row)
postgres=# SELECT current_setting('my.var');
current_setting
-----------------
5
(1 row)
现在,你将
2
设置为my.var
,然后调用my_proc(0)
,然后division by zero
发生错误,那么my.var
仍然是2
,如下所示,因为my_proc()
过程已回滚:
postgres=# SET my.var = 2;
SET
postgres=# CALL my_proc(0);
ERROR: division by zero
...
postgres=# SELECT current_setting('my.var');
current_setting
-----------------
2
(1 row)