PostgreSQL函数是事务性的吗?

时间:2012-10-08 08:48:42

标签: 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;


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

5 个答案:

答案 0 :(得分:70)

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

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

regress=# BEGIN;
BEGIN
regress=# SELECT 1/0;
ERROR:  division by zero
regress=# COMMIT;
ROLLBACK

查看由于零分割而处于错误状态的交易如何回滚COMMIT

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

BEGIN;
SELECT refresh_materialized_view(name);
COMMIT;

(如果COMMIT引发错误,SELECT将失败。

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

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

答案 1 :(得分:23)

由于我对PostgreSQL的了解不如Craig Ringer,我会尝试给出一个较短的答案:是的。

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

此外,如果您在PgAdmin中执行查询同样的事情。

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

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

select anything_that_do_not_exists;

id = 20行[{1}}中的更新不会保存在数据库中。

更新时间 - 2018年9月

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

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

your_table

然后,让我们执行:

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;

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

答案 2 :(得分:5)

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

调用该函数

select schemaName.functionName()

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

答案 3 :(得分:3)

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

  

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

答案 4 :(得分:0)

此外,ATOMIC 事务也包括触发器。