存储过程是否在Postgres中的数据库事务中运行?

Har*_*mal 12 database postgresql stored-procedures transactions relational-database

如果存储过程在中间失败,那么从SP开始的那一点的更改是否隐式回滚,或者我们是否必须编写任何显式代码以确保SP仅在数据库事务中运行?

Erw*_*ter 25

严格来说,Postgres目前(包括版本10)不具有 ANSI标准中定义的"存储过程".一切都是用"函数"完成的,它们提供了与其他RDBMS提供的存储过程相同的功能(和更多).主要区别在于交易处理.

Postgres 11最终引入了真正的存储过程:

函数在Postgres中是原子的,并且在自己的事务中自动运行,除非在外部事务中调用.它们总是在单个事务中运行,并且完全成功或失败.因此,无法在函数内开始或提交事务.并且不允许使用VACUUMCREATE DATABASE不能在事务块中运行的命令.

关于PL/pgSQL的每个文档:

函数和触发器过程总是在外部查询建立的事务中执行 - 它们无法启动或提交该事务,因为它们没有上下文可供执行.但是,包含CREATE INDEX CONCURRENTLY子句的块有效地形成了一个子事务,可以是回滚而不影响外部交易.

错误处理:

默认情况下,PL/pgSQL函数中发生的任何错误都会中止函数的执行,也会中止周围事务的执行.您可以使用EXCEPTION 带有BEGIN子句的块来捕获错误并从中恢复.

有特殊例外,包括但不限于:

  • 写入日志文件的数据
  • 对序列所做的更改

    重要:一些PostgreSQL数据类型和函数有关于事务行为的特殊规则.特别是,对序列(以及因此声明的列的计数器EXCEPTION)所做的更改对所有其他事务立即可见,并且如果进行更改的事务中止,则不会回滚.

  • 准备好的陈述

  • dblink调用(或类似)


Bin*_*ati 6

如果您使用的是 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
$$;
Run Code Online (Sandbox Code Playgroud)

出于所有实际目的,在BEGINEND块之间编写的代码在单个事务中执行。因此,如果块中的任何语句失败,则所有先前的语句将自动回滚。您不需要显式编写任何回滚代码。

但是,在某些特殊情况下,人们可以对何时启动/提交/回滚事务进行细粒度控制。有关详细信息,请参阅:https://www.postgresql.org/docs/current/plpgsql-transactions.html 。