如果存储过程在中间失败了,那么从存储过程开始到失败点的更改会隐式回滚吗?还是我们需要编写任何显式代码来确保存储过程只在数据库事务中运行?
如果存储过程在中间失败了,那么从存储过程开始到失败点的更改会隐式回滚吗?还是我们需要编写任何显式代码来确保存储过程只在数据库事务中运行?
函数在Postgres中是原子性的。 它们始终在事务上下文中运行,并且要么完全成功,要么完全失败。 因此,在函数内部无法开始或提交事务。而不在事务上下文中运行的命令,如VACUUM
、CREATE DATABASE
或CREATE INDEX CONCURRENTLY
是不允许的。
默认情况下,PL/pgSQL函数中发生的任何错误都会中止函数的执行,甚至中止周围事务的执行。您可以使用带有函数和触发器过程总是在外部查询建立的事务中执行 - 它们不能启动或提交该事务,因为它们没有执行的上下文。然而,包含
EXCEPTION
子句的块实际上形成了一个可以回滚而不影响外部事务的子事务。
BEGIN
块和EXCEPTION
子句来捕获错误并从中恢复。数据写入日志文件
重要提示:某些 PostgreSQL 数据类型和函数在事务行为方面有特殊规则。特别是,对序列的更改(因此也包括使用
serial
声明的列的计数器)立即对所有其他事务可见,并且如果进行更改的事务中止,则不会回滚。
预编译语句
SQL Fiddle 演示
dblink 调用(或类似操作)
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
块中编写的代码将在一个事务中执行。因此,如果块中的任何语句失败,所有先前的语句都将自动回滚。您不需要显式编写任何回滚代码。来自Postgresql的官方文件:
在由CALL命令调用的过程以及匿名代码块(DO命令)中,可以使用COMMIT和ROLLBACK命令结束事务。在使用这些命令结束事务后,会自动启动一个新的事务,因此没有单独的START TRANSACTION命令。(请注意,PL/pgSQL中BEGIN和END具有不同的含义。)
https://www.postgresql.org/docs/11/plpgsql-transactions.html