37

plpgsql関数でアトミックトランザクションを確実にする方法と、データベースへのこの特定の変更に対して分離レベルが設定されている場所の明確化を求めています。

以下に示すplpgsql関数では、削除と挿入の両方が成功することを確認したいと思います。それらを単一のトランザクションでラップしようとすると、エラーが発生します。

ERROR:  cannot begin/end transactions in PL/pgSQL

この関数がカスタム行を削除した、カスタムを挿入するに、別のユーザーが状況('RAIN'、'NIGHT'、 '45MPH')のデフォルトの動作を追加した場合、以下の関数の実行中に何が起こりますか行?別のユーザーがこの関数によって参照される行のいずれかを変更した場合に両方がロールバックされるように、挿入と削除をラップする暗黙のトランザクションはありますか?この関数の分離レベルを設定できますか?

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;
4

2 に答える 2

47

plpgsql関数はトランザクション内で自動的に実行されます。それはすべて成功するか、すべて失敗します。マニュアル:

関数とトリガープロシージャは、常に外部クエリによって確立されたトランザクション内で実行されます。実行するコンテキストがないため、そのトランザクションを開始またはコミットすることはできません。ただし、句を含むブロックは、EXCEPTION次のようなサブトランザクションを効果的に形成します。外部トランザクションに影響を与えることなくロールバックされました。詳細については、セクション42.6.6を参照してください。

したがって、必要に応じて、理論的に発生する可能性のある例外をキャッチできます(ただし、発生する可能性はほとんどありません)。
マニュアルのトラップエラーの詳細。

あなたの機能はレビューされ、簡素化されました:

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以降のSQLプロシージャCREATE PROCEDUREを参照してください( )。見る:

于 2013-01-27T17:55:46.270 に答える
1

更新:PostgreSQLバージョン11以降、ストアドプロシージャ内でトランザクションを制御できます。

=====バージョン10より前:

START TRANSACTION;
select foo() ;
COMMIT;

「残念ながら、Postgresにはストアドプロシージャがないため、常に呼び出し元のコードでトランザクションを管理する必要があります」– a_horse_with_no_name

例外ブロックでのトランザクション-どのように?

于 2018-04-09T19:47:17.753 に答える