85

次のような 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;


つまり、関数の実行中にエラーが発生した場合、変更はロールバックされますか? これがデフォルトの動作でない場合、どうすれば関数をトランザクション化できますか?

4

5 に答える 5

96

PostgreSQL 12 の更新:トランザクション制御を実行できるトップレベルの s のサポートが制限されてPROCEDUREいます。通常の SQL 呼び出し可能関数でトランザクションを管理することはまだできないため、新しい最上位プロシージャを使用する場合を除いて、以下は当てはまります。


関数は、呼び出し元のトランザクションの一部です。トランザクションがロールバックすると、それらの効果はロールバックされます。トランザクションがコミットされると、それらの作業がコミットされます。関数内のすべてのブロックは、およびSQL ステートメントBEGIN ... EXCEPTのようなセーブポイントのように動作します (内部では使用されます) 。SAVEPOINTROLLBACK TO SAVEPOINT

BEGIN ... EXCEPT関数は、エラー処理を除いて、完全に成功するか、完全に失敗します。関数内でエラーが発生し、処理されない場合、関数を呼び出すトランザクションは中止されます。中止されたトランザクションはコミットできず、コミットしようとすると、エラーが発生した他のトランザクションと同様に としてCOMMIT扱われます。ROLLBACK観察:

regress=# BEGIN;
BEGIN
regress=# SELECT 1/0;
ERROR:  division by zero
regress=# COMMIT;
ROLLBACK

ゼロ除算によりエラー状態にあるトランザクションがロールバックする様子をご覧くださいCOMMIT

明示的な周囲のトランザクションなしで関数を呼び出す場合、ルールは他の Pg ステートメントとまったく同じです。

BEGIN;
SELECT refresh_materialized_view(name);
COMMIT;

(エラーが発生したCOMMIT場合は失敗SELECTします)。

PostgreSQL は、プロシージャ/関数が呼び出し元のトランザクションとは無関係にコミット/ロールバックできる関数での自律型トランザクションを (まだ) サポートしていません。これは、 dblinkを介して新しいセッションを使用してシミュレートできます。

しかし、PostgreSQL には、トランザクションに対応していないものや不完全にトランザクションに対応しているものがあります。通常のBEGIN; do stuff; COMMIT;ブロックで非トランザクション動作を行う場合、関数でも非トランザクション動作を行います。たとえば、nextvalsetvalTRUNCATEなどです。

于 2012-10-08T09:19:19.120 に答える
12

https://www.postgresql.org/docs/current/static/plpgsql-structure.html

PL/pgSQL でステートメントをグループ化するための BEGIN/END の使用を、トランザクション制御のための同様の名前の SQL コマンドと混同しないことが重要です。PL/pgSQL の BEGIN/END はグループ化専用です。トランザクションを開始または終了しません。関数とトリガー プロシージャは、外部クエリによって確立されたトランザクション内で常に実行されます。実行するコンテキストがないため、そのトランザクションを開始またはコミットすることはできません。外部トランザクションに影響を与えずにロールバックされます。詳細については、セクション 39.6.6 を参照してください。

于 2016-10-31T10:59:31.783 に答える
7

機能レベルでは、それは国境を越えていません。つまり、関数内の各ステートメントは、デフォルトの db auto commit 値である単一のトランザクションに属します。自動コミットはデフォルトで true です。とにかく、次を使用して関数を呼び出す必要があります

select schemaName.functionName()

上記のステートメント 'select schemaName.functionName()' は単一のトランザクションです。トランザクションに T1 という名前を付けましょう。したがって、関数内のすべてのステートメントはトランザクション T1 に属します。このように、関数は単一のトランザクション内にあります。

于 2016-03-02T19:59:30.300 に答える