PostgreSQL:在plpgsql函数中回滚事务?

jam*_*ieb 10 postgresql transactions plpgsql

来自MS SQL世界,我倾向于大量使用存储过程.我目前正在编写一个应用程序使用了很多PostgreSQL plpgsql函数.我想做的是回滚特定函数中包含的所有INSERTS/UPDATES如果我在其中的任何一点得到异常.

我最初的印象是每个函数都包含在它自己的事务中,并且异常会自动回滚所有内容.但是,情况似乎并非如此.我想知道我是否应该将保存点与异常处理结合使用?但我并不真正了解事务和保存点之间的区别,以了解这是否是最好的方法.有什么建议吗?

CREATE OR REPLACE FUNCTION do_something(
         _an_input_var int
                ) RETURNS bool AS $$
        DECLARE
                _a_variable int;
        BEGIN
                INSERT INTO tableA (col1, col2, col3)
                        VALUES (0, 1, 2);

                INSERT INTO tableB (col1, col2, col3)
                        VALUES (0, 1, 'whoops! not an integer');

                -- The exception will cause the function to bomb, but the values 
                -- inserted into "tableA" are not rolled back.    

                RETURN True;
END; $$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

小智 14

函数确实代表一个事务.您不必在BEGIN/COMMIT中包装函数.

  • @Frank:但那是因为外部交易.在同一语句中调用的其他函数中的插入或事务中的先前语句也将失败.除非使用保存点,否则无法回滚函数中的插入而不回滚外部事务的其他结果.函数体总是在事务中执行,但它本身不是事务.没有办法调用函数没有启动事务. (10认同)
  • 对于PostgreSQL来说,情况并非如此.单个SQL语句在未作为显式事务的一部分执行时(不在BEGIN和COMMIT/END之间执行)作为单个事务执行.但是如果这样的语句调用多个函数,那么所有函数都在一个事务中执行.此外,当您有多个语句事务(显式BEGIN,COMMIT)并且这些语句调用某些过程时,所有这些都将在单个事务中执行.正如其他人所说:保存点是要走的路. (7认同)
  • @Jacek:约书亚是对的,一个函数确实代表了它自己的交易.您不需要保存点来回滚两个插入,如果一个失败,它们都将失败. (2认同)