PostgreSQL函数是事务性的吗?

Dón*_*nal 66 postgresql transactions

PostgreSQL函数如下面的自动事务是什么?

CREATE OR REPLACE FUNCTION refresh_materialized_view(name)
  RETURNS integer AS
$BODY$
 DECLARE
     _table_name ALIAS FOR $1;
     _entry materialized_views%ROWTYPE;
     _result INT;
 BEGIN          

     EXECUTE 'TRUNCATE TABLE ' || _table_name;

     UPDATE materialized_views
     SET    last_refresh = CURRENT_TIMESTAMP
     WHERE  table_name = _table_name;

     RETURN 1;
END
$BODY$
  LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
Run Code Online (Sandbox Code Playgroud)


换句话说,如果在执行函数期间发生错误,是否会回滚任何更改?如果这不是默认行为,我该如何使该函数成为事务性的

Cra*_*ger 78

函数是他们调用的事务的一部分.如果事务回滚,它们的效果将被回滚.如果事务提交,他们的工作将提交.PROCEDURE函数中的任何块都像(和在引擎盖下使用)一样运行保存点,如SQL语句BEGIN ... EXCEPTSAVEPOINTSQL语句.

除了ROLLBACK TO SAVEPOINT错误处理之外,该功能要么全部成功要么全部失败.如果在函数内引发错误而未处理,则中止调用该函数的事务.中止的事务无法提交,如果它们尝试提交,BEGIN ... EXCEPT则视为与COMMIT错误的任何其他事务相同.注意:

regress=# BEGIN;
BEGIN
regress=# SELECT 1/0;
ERROR:  division by zero
regress=# COMMIT;
ROLLBACK
Run Code Online (Sandbox Code Playgroud)

看看由于零分割而处于错误状态的事务如何回滚ROLLBACK

如果在没有明确的外围事务的情况下调用函数,则规则与任何其他Pg语句完全相同:

BEGIN;
SELECT refresh_materialized_view(name);
COMMIT;
Run Code Online (Sandbox Code Playgroud)

(COMMIT如果COMMIT引发错误,将在哪里失败).

PostgreSQL(还)不支持函数中的自治事务,其中过程/函数可以独立于调用事务提交/回滚.这可以通过dblink使用新会话进行模拟.

但是,PostgreSQL中存在非事务性或不完全事务性的事物.如果它在正常SELECT块中具有非事务性行为,则它在函数中也具有非事务性行为.例如,BEGIN; do stuff; COMMIT;nextval,setval等.

  • 非常清楚的解释。特别感谢您用简短的实例来说明您的答案。 (2认同)

Ign*_*cio 26

由于我对PostgreSQL的了解不如Craig Ringer那么深,我会尝试给出一个更简短的答案:是的.

如果执行其中包含错误的函数,则任何步骤都不会影响数据库.

此外,如果您执行同一个查询PgAdmin.

例如,如果您在查询中执行:

update your_table yt set column1 = 10 where yt.id=20;

select anything_that_do_not_exists;
Run Code Online (Sandbox Code Playgroud)

该行的更新id = 20your_table不会被保存在数据库中.

更新于2008年9月至2018年

为了澄清这个概念,我用非事务函数nextval做了一个小例子.

首先,让我们创建一个序列:

create sequence test_sequence start 100;

然后,让我们执行:

update your_table yt set column1 = 10 where yt.id=20; select nextval('test_sequence'); select anything_that_do_not_exists;

现在,如果我们打开另一个查询并执行

select nextval('test_sequence');

我们将获得101因为第一个值(100)在后一个查询中使用(这是因为序列不是事务性的),尽管未提交更新.

  • 谢谢你明确的答案!看完克雷格的回答后,我感到不安. (3认同)
  • 比克雷格的答案好得多 (2认同)

小智 6

https://www.postgresql.org/docs/current/static/plpgsql-structure.html

重要的是不要混淆使用BEGIN / END将PL / pgSQL中的语句与类似名称的SQL命令进行事务控制进行分组。PL / pgSQL的BEGIN / END仅用于分组;他们不开始或结束交易。函数和触发器过程始终在由外部查询建立的事务中执行-它们无法启动或提交该事务,因为将没有上下文可在其中执行。但是,包含EXCEPTION子句的块有效地形成了一个子事务,该子事务可以在不影响外部交易的情况下回滚。有关更多信息,请参见第39.6.6节。


Bin*_*ati 6

BEGINPostgres 14 更新:在过程/函数的和块之间写入的所有语句都END在单个事务中执行。因此,执行该块时出现的任何错误都将导致事务自动回滚。


Rob*_*bin 5

在功能层面,它不是跨国的.换句话说,函数中的每个语句都属于单个事务,这是默认的db auto commit值.默认情况下,自动提交为true.但无论如何,你必须使用函数调用

select schemaName.functionName()

上面的语句'select schemaName.functionName()'是单个事务,让我们将事务命名为T1,因此函数中的所有语句都属于事务T1.通过这种方式,该功能处于单个事务中.