postgresql plpgsql函数是原子函数吗?

cuxqih21  于 12个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(130)

我想知道plpgsql函数调用和嵌套调用的原子性:
例如,我想将两条信息放入两个不同的表中:

CREATE OR REPLACE FUNCTION email_registration(
  i_email TEXT,
  i_nickname TEXT
) RETURNS JSONB AS $$
BEGIN
  DECLARE
    o_account "UserAccount";
    o_identity "UserIdentity";
  BEGIN
    INSERT INTO "UserAccount"  (nickname) VALUES (i_nickname) RETURNING * INTO o_account;
    INSERT INTO "UserIdentity" (email) VALUES (i_email) RETURNING * INTO o_identity;
    RETURN jsonb_build_object(
        'account',row_to_json(o_account), 
         'identity',row_to_json(o_identity)
    );
  END;
END;
$$ LANGUAGE 'plpgsql';

字符串
调用email_registration('hello', 'world')是否会导致helloUserAccount表中,而worldUserIdentity表中丢失?
另外,如果这两个插入被重构为函数,函数调用是否仍然是原子的?
ie.

CREATE OR REPLACE FUNCTION email_registration(
  i_email TEXT,
  i_nickname TEXT
) RETURNS JSONB AS $$
BEGIN
  DECLARE
    o_account "UserAccount";
    o_identity "UserIdentity";
  BEGIN
    o_account := insert_email(i_email);
    o_identity := insert_nickname(i_nickname);
    RETURN jsonb_build_object(
        'account',row_to_json(o_account), 
         'identity',row_to_json(o_identity)
    );
  END;
END;
$$ LANGUAGE 'plpgsql';

luaexgnf

luaexgnf1#

函数总是在函数调用开始时处于活动状态的单个事务中运行,因此,要么所有语句都成功,要么所有语句都失败。这是可以保证的。
还有其他一些事情可能导致INSERT无效,例如返回NULL的行级BEFORE触发器。

3bygqnnd

3bygqnnd2#

是的,函数(PL/pgSQL functionsSQL functions)是原子的。函数在事务中运行,所以如果有错误,事务会回滚。
例如,您创建my_func()函数,将5设置为my.var,然后可能导致division by zero错误,如下所示:

CREATE FUNCTION my_func(value INTEGER) RETURNS INTEGER AS $$
BEGIN
SET my.var = 5; -- Here
RETURN 1/value;
END;
$$ LANGUAGE plpgsql;

字符串
首先,您将2设置为my.var,然后调用my_func(1),然后5成功设置为my.var,如下所示:

postgres=# SET my.var = 2;
SET
postgres=# SELECT my_func(1);
 my_func
---------
       1
(1 row)
postgres=# SELECT current_setting('my.var');
 current_setting
-----------------
 5
(1 row)


现在,您将2设置为my.var,然后调用my_func(0),然后发生division by zero错误,然后my.var仍然是2,如下所示,因为my_func()函数被回滚:

postgres=# SET my.var = 2;
SET
postgres=# SELECT my_func(0);
ERROR:  division by zero
...
postgres=# SELECT current_setting('my.var');
 current_setting
-----------------
 2
(1 row)

相关问题