在PostgreSQL中,过程是否在事务中运行?

k5hmc34c  于 5个月前  发布在  PostgreSQL
关注(0)|答案(4)|浏览(79)

如果一个过程中途失败,那么从SP开始的那一点上的更改是隐式回滚的,还是必须编写任何显式代码来确保SP仅在事务中运行?

xmakbtuz

xmakbtuz1#

这个术语经常被错误地用来指函数CREATE FUNCTION),它提供了与其他RDBMS提供的“存储过程”相同的功能(甚至更多)。
ISO/IEC标准中定义的真正的存储过程CREATE PROCEDURE)是在Postgres 11中引入的。主要区别(除其他外)是事务处理。请参阅:

它们中的任何一个总是在事务上下文中运行The manual
PostgreSQL实际上将每个SQL语句视为在事务中执行。如果您没有发出BEGIN命令,则每个单独的语句都有一个隐式的BEGIN和(如果成功)COMMIT

Functions

.不能COMMIT.他们是 * 原子 * -**他们成功或失败 * 完全 .
好吧,PL/pgSQL中有错误处理。手册:
默认情况下,PL/pgSQL函数中发生的任何错误都会中止该函数和周围事务的执行。您可以使用带有EXCEPTION子句的BEGIN块捕获错误并从中恢复。
不要混淆PL/pgSQL BEGIN(代码块的开始)和SQL BEGIN(事务的开始)。

Procedures

... allow COMMIT-这会立即启动一个新的事务。
一个新的事务开始时具有默认的事务特征,如事务隔离级别。如果事务是在循环中提交的,可能需要自动启动具有与前一个事务相同特征的新事务。命令COMMIT AND CHAINROLLBACK AND CHAIN可以实现这一点。

VACUUMCREATE DATABASECREATE INDEX CONCURRENTLY这样的命令不能在事务上下文中运行,也不允许在内部运行。
有些事情永远无法回滚,包括:

  • 写入日志文件的数据
  • 对序列所做的更改. The manual:
    重要:某些PostgreSQL数据类型和函数有关于事务行为的特殊规则。特别是,对序列(以及使用serial声明的列的计数器)的更改对所有其他事务立即可见,并且如果进行更改的事务中止,则不会回滚。
  • 预处理语句(旧的sqlfiddle演示)
  • dblink调用(或类似)。请参阅:
  • Postgres支持嵌套或自治事务吗?
dbf7pr2w

dbf7pr2w2#

如果您使用的是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
$$;

字符串
实际上,写在BEGINEND块之间的代码是在一个事务中执行的。因此,如果块中的任何语句失败,前面的所有语句都会自动回滚。您不需要显式地编写任何回滚代码。
然而,在某些特殊情况下,可以对何时启动/提交/回滚事务进行细粒度控制。有关详细信息,请参阅:https://www.postgresql.org/docs/current/plpgsql-transactions.html

xkrw2x1b

xkrw2x1b3#

来自Postgresql的官方文档:
在由CALL命令调用的过程以及匿名代码块(DO命令)中,可以使用命令COMMIT和ROLLBACK结束事务。在使用这些命令结束事务后,新事务会自动启动,因此没有单独的START TRANSACTION命令。(请注意,开始和END在PL/pgSQL中具有不同的含义。)
https://www.postgresql.org/docs/11/plpgsql-transactions.html

p4rjhz4m

p4rjhz4m4#

过程在事务中运行,因此如果出现错误,事务将回滚。
例如,您创建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)

相关问题