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;
换句话说,如果在函数执行过程中发生错误,是否会 * 回滚 * 任何更改?如果这不是默认行为,我如何使函数成为事务性的?
6条答案
按热度按时间kgqe7b3p1#
PostgreSQL 12更新:there is limited support for top-level
PROCEDURE
s that can do transaction control。您仍然无法在常规的SQL可调用函数中管理事务,因此除非使用新的顶级过程,否则以下内容仍然适用。函数是调用它们的事务的一部分。如果事务回滚,则回滚它们的影响。如果事务提交,则它们的工作也会提交。函数中的任何
BEGIN ... EXCEPT
块的操作类似于(并且在后台使用)保存点,如SAVEPOINT
和ROLLBACK TO SAVEPOINT
SQL语句。该函数要么完全成功,要么完全失败,排除
BEGIN ... EXCEPT
错误处理。如果在函数中引发错误但未处理,则调用该函数的事务将中止。被中止的事务不能提交,如果它们试图提交,COMMIT
将被视为ROLLBACK
,与任何其他错误的事务相同。观察:查看由于零除法而处于错误状态的事务如何在
COMMIT
上回滚?如果你调用一个没有显式环绕事务的函数,规则与任何其他Pg语句完全相同:
(如果
SELECT
引发错误,则COMMIT
将失败)。PostgreSQL还不支持函数中的自治事务,其中过程/函数可以独立于调用事务提交/回滚。这可以通过dblink使用新会话进行模拟。
但是,PostgreSQL中存在非事务性或不完全事务性的东西。如果它在普通的
BEGIN; do stuff; COMMIT;
块中具有非事务性行为,那么它在函数中也具有非事务性行为。例如,nextval
和setval
、TRUNCATE
等。tag5nh1u2#
由于我对PostgreSQL的了解不如克雷格Ringer那么深,我将尝试给予一个简短的答案:是的
如果你执行一个有错误的函数,那么这些步骤都不会影响数据库。
此外,如果在
PgAdmin
中执行查询,也会发生同样的情况。例如,如果在查询中执行:
your_table
的id = 20
行中的更新不会保存在数据库中。2018年9月更新
为了澄清这个概念,我用非事务函数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)在后一个查询中使用(这是因为序列不是事务性的),尽管更新没有提交。
jchrr9hc3#
https://www.postgresql.org/docs/current/static/plpgsql-structure.html
不要将PL/pgSQL中用于分组语句的开始/END与用于事务控制的名称相似的SQL命令混淆,这一点很重要。PL/pgSQL的开始/END只用于分组;它们不开始或结束事务。函数和触发器过程总是在由外部查询建立的事务中执行-它们不能启动或提交该事务,因为没有上下文供它们执行。但是,包含EXCEPTION子句的块有效地形成了一个子事务,可以回滚该子事务而不影响外部事务。有关更多信息,请参见第39.6.6节。
esbemjvw4#
在功能层面上,它不是跨国的。换句话说,函数中的每个语句都属于单个事务,这是默认的db auto commit值。默认情况下,自动提交为true。但无论如何,您必须使用
select schemaName.functionName()
上面的语句'select schemaName.functionName()'是一个事务,我们将事务命名为T1,因此函数中的所有语句都属于事务T1。这样,该函数在单个事务中。
ma8fv8wu5#
Postgres 14更新:在过程/函数的
BEGIN
和END
块之间写入的所有语句都在单个事务中执行。因此,执行此块时出现的任何错误都将导致事务的自动回滚。jobtbby36#
此外,ATOMIC事务也包括触发器。