如果一个过程中途失败,那么从SP开始的那一点上的更改是隐式回滚的,还是必须编写任何显式代码来确保SP仅在事务中运行?
xmakbtuz1#
这个术语经常被错误地用来指函数(CREATE FUNCTION),它提供了与其他RDBMS提供的“存储过程”相同的功能(甚至更多)。ISO/IEC标准中定义的真正的存储过程(CREATE PROCEDURE)是在Postgres 11中引入的。主要区别(除其他外)是事务处理。请参阅:
CREATE FUNCTION
CREATE PROCEDURE
它们中的任何一个总是在事务上下文中运行。The manual:PostgreSQL实际上将每个SQL语句视为在事务中执行。如果您没有发出BEGIN命令,则每个单独的语句都有一个隐式的BEGIN和(如果成功)COMMIT。
BEGIN
COMMIT
.不能COMMIT.他们是 * 原子 * -**他们成功或失败 * 完全 .好吧,PL/pgSQL中有错误处理。手册:默认情况下,PL/pgSQL函数中发生的任何错误都会中止该函数和周围事务的执行。您可以使用带有EXCEPTION子句的BEGIN块捕获错误并从中恢复。不要混淆PL/pgSQL BEGIN(代码块的开始)和SQL BEGIN(事务的开始)。
EXCEPTION
... allow COMMIT-这会立即启动一个新的事务。一个新的事务开始时具有默认的事务特征,如事务隔离级别。如果事务是在循环中提交的,可能需要自动启动具有与前一个事务相同特征的新事务。命令COMMIT AND CHAIN和ROLLBACK AND CHAIN可以实现这一点。
COMMIT AND CHAIN
ROLLBACK AND CHAIN
像VACUUM、CREATE DATABASE或CREATE INDEX CONCURRENTLY这样的命令不能在事务上下文中运行,也不允许在内部运行。有些事情永远无法回滚,包括:
VACUUM
CREATE DATABASE
CREATE INDEX CONCURRENTLY
serial
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 $$;
字符串实际上,写在BEGIN和END块之间的代码是在一个事务中执行的。因此,如果块中的任何语句失败,前面的所有语句都会自动回滚。您不需要显式地编写任何回滚代码。然而,在某些特殊情况下,可以对何时启动/提交/回滚事务进行细粒度控制。有关详细信息,请参阅:https://www.postgresql.org/docs/current/plpgsql-transactions.html。
END
xkrw2x1b3#
来自Postgresql的官方文档:在由CALL命令调用的过程以及匿名代码块(DO命令)中,可以使用命令COMMIT和ROLLBACK结束事务。在使用这些命令结束事务后,新事务会自动启动,因此没有单独的START TRANSACTION命令。(请注意,开始和END在PL/pgSQL中具有不同的含义。)https://www.postgresql.org/docs/11/plpgsql-transactions.html
p4rjhz4m4#
过程在事务中运行,因此如果出现错误,事务将回滚。例如,您创建my_proc()过程,将5设置为my.var,然后可能导致division by zero错误,如下所示:
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,如下所示:
2
my_proc(1)
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()过程被回滚:
my_proc(0)
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)
型
4条答案
按热度按时间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
(代码块的开始)和SQLBEGIN
(事务的开始)。Procedures
... allow
COMMIT
-这会立即启动一个新的事务。一个新的事务开始时具有默认的事务特征,如事务隔离级别。如果事务是在循环中提交的,可能需要自动启动具有与前一个事务相同特征的新事务。命令
COMMIT AND CHAIN
和ROLLBACK AND CHAIN
可以实现这一点。像
VACUUM
、CREATE DATABASE
或CREATE INDEX CONCURRENTLY
这样的命令不能在事务上下文中运行,也不允许在内部运行。有些事情永远无法回滚,包括:
重要:某些PostgreSQL数据类型和函数有关于事务行为的特殊规则。特别是,对序列(以及使用
serial
声明的列的计数器)的更改对所有其他事务立即可见,并且如果进行更改的事务中止,则不会回滚。dbf7pr2w2#
如果您使用的是Postgres 14,则如下所示:
字符串
实际上,写在
BEGIN
和END
块之间的代码是在一个事务中执行的。因此,如果块中的任何语句失败,前面的所有语句都会自动回滚。您不需要显式地编写任何回滚代码。然而,在某些特殊情况下,可以对何时启动/提交/回滚事务进行细粒度控制。有关详细信息,请参阅:https://www.postgresql.org/docs/current/plpgsql-transactions.html。
xkrw2x1b3#
来自Postgresql的官方文档:
在由CALL命令调用的过程以及匿名代码块(DO命令)中,可以使用命令COMMIT和ROLLBACK结束事务。在使用这些命令结束事务后,新事务会自动启动,因此没有单独的START TRANSACTION命令。(请注意,开始和END在PL/pgSQL中具有不同的含义。)
https://www.postgresql.org/docs/11/plpgsql-transactions.html
p4rjhz4m4#
过程在事务中运行,因此如果出现错误,事务将回滚。
例如,您创建
my_proc()
过程,将5
设置为my.var
,然后可能导致division by zero
错误,如下所示:字符串
首先,您将
2
设置为my.var
,然后调用my_proc(1)
,然后5
成功设置为my.var
,如下所示:型
现在,您将
2
设置为my.var
,然后调用my_proc(0)
,然后发生division by zero
错误,然后my.var
仍然是2
,如下所示,因为my_proc()
过程被回滚:型