PostgreSQL不能在PL/pgSQL中开始/结束事务

nfs0ujit  于 4个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(76)

我正在寻求澄清如何确保在一个plpgsql函数中的原子事务,以及在哪里为这个特定的数据库更改设置隔离级别。
在如下所示的plpgsql函数中,我想确保删除和插入都成功。当我试图将它们 Package 在单个事务中时,我得到了一个错误:

ERROR:  cannot begin/end transactions in PL/pgSQL

字符串
如果另一个用户添加了默认行为,在执行下面的函数时会发生什么?('RAIN','NIGHT',' 45MPH')* 在 * 此函数删除了自定义行之后,但 * 在 * 它有机会插入自定义行之前?是否有隐式事务 Package 插入和删除,以便在另一个用户更改了功能?我可以设置此功能的隔离级别吗?

create function foo(v_weather varchar(10), v_timeofday varchar(10), v_speed varchar(10),
   v_behavior varchar(10))
   returns setof CUSTOMBEHAVIOR
   as $body$
   begin
      -- run-time error if either of these lines is un-commented

      -- start transaction ISOLATION LEVEL READ COMMITTED;
      -- or, alternatively, set transaction ISOLATION LEVEL READ COMMITTED;

      delete from CUSTOMBEHAVIOR 
      where weather = 'RAIN' and timeofday = 'NIGHT' and speed= '45MPH' ;

      -- if there is no default behavior insert a custom behavior

      if not exists
        (select id from DEFAULTBEHAVIOR where a = 'RAIN' and b = 'NIGHT' and c= '45MPH') then
         insert into CUSTOMBEHAVIOR
           (weather, timeofday, speed, behavior)
         values
           (v_weather, v_timeofday, v_speed, v_behavior);
      end if;

      return QUERY
      select * from CUSTOMBEHAVIOR where ...   ;

      -- commit;
   end
   $body$  LANGUAGE plpgsql;

gz5pxeao

gz5pxeao1#

PL/pgSQL函数在transaction中自动运行,要么全部成功,要么全部失败。请参阅:

如果需要,可以捕获理论上可能发生(但不太可能)的异常。
手册中有关捕获错误的详细信息。
您的功能已审核并简化:

CREATE FUNCTION foo(v_weather text
                  , v_timeofday text
                  , v_speed text
                  , v_behavior text)
  RETURNS SETOF custombehavior
  LANGUAGE plpgsql AS
$func$
BEGIN
   DELETE FROM custombehavior
   WHERE  weather   = 'RAIN'
   AND    timeofday = 'NIGHT'
   AND    speed     = '45MPH';

   INSERT INTO custombehavior
         (  weather,   timeofday,   speed,   behavior)
   SELECT v_weather, v_timeofday, v_speed, v_behavior
   WHERE  NOT EXISTS (
      SELECT FROM defaultbehavior
      WHERE  a = 'RAIN'
      AND    b = 'NIGHT'
      AND    c = '45MPH'
      );

   RETURN QUERY
   SELECT * FROM custombehavior WHERE ... ;
END
$func$;

字符串
如果你真的需要像标题中指出的那样 * 开始/结束事务 *,请查看Postgres 11或更高版本(CREATE PROCEDURE)中的SQL过程。(但过程目前无法返回集合。)请参阅:

  • 在PostgreSQL中,“存储过程”和其他类型的函数有什么区别?

此外,您可能希望将INSERTDELETE替换为“UPSERT”,以安全地处理竞争条件。请参阅:

qnyhuwrf

qnyhuwrf2#

更新:在PostgreSQL版本11之后,你可以在存储过程中控制事务。
=在版本10之前:

START TRANSACTION;
select foo() ;
COMMIT;

字符串
“不幸的是,Postgres没有存储过程,所以你总是需要在调用代码中管理事务”- a_horse_with_no_name
Transaction in an exception block - how?

相关问题