3

PostgreSQL ドキュメンテーション マニュアルhttp://www.postgresql.org/docs/8.3/interactive/populate.htmlの次のリンクは、 postgreSQL で自動コミットを無効にするには、すべての挿入ステートメントを BEGIN 内に配置するだけでよいと述べています。およびコミット;

ただし、BEGIN の間に発生する可能性のある例外をキャプチャするのは困難です。専念; エラーが発生した場合 (重複した PK を挿入しようとするなど)、ROLLBACK または COMMIT コマンドを明示的に呼び出す方法がありません。すべての挿入ステートメントは自動的にロールバックされますが、PostgreSQL は、トランザクションが終了したと見なす前に、COMMIT または ROLLBACK コマンドのいずれかへの明示的な呼び出しを想定しています。そうしないと、スクリプトはトランザクションがタイムアウトするまで待機する必要があり、その後にステートメントを実行するとエラーが発生します。

ストアド プロシージャでは、EXCEPTION 句を使用してこれを行うことができますが、一括挿入を実行する私の状況では同じことが当てはまりません。私はそれを試しましたが、エラーが発生した後に実行された次のステートメントがエラーで実行に失敗したため、例外ブロックは機能しませんでした:

ERROR:  current transaction is aborted, commands ignored until end of transaction block

COMMIT または ROLLBACK の呼び出しで明示的にファイナライズされていないため、トランザクションは開いたままです。

これをテストするために使用したコードのサンプルを次に示します。

BEGIN;
  SET search_path TO testing;
  INSERT INTO friends (id, name) VALUES (1, 'asd');
  INSERT INTO friends (id, name) VALUES (2, 'abcd');
    INSERT INTO friends (id, nsame) VALUES (2, 'abcd'); /*note the deliberate mistake in  attribute name and also the deliberately repeated pk value number 2*/
EXCEPTION /* this part does not work for me */
    WHEN OTHERS THEN
        ROLLBACK;   
COMMIT;

そのような手法を使用する場合、すべてのステートメントが成功することを本当に保証する必要がありますか? これはなぜですか?エラーをトラップして明示的にロールバックを呼び出す方法はありませんか?

ありがとうございました

4

2 に答える 2

2

beginとcommitの間に実行すると、例外が発生した場合にすべてが自動的にロールバックされます。投稿したURLからの抜粋:「1つのトランザクションですべての挿入を行うことの追加の利点は、1つの行の挿入が失敗した場合、その時点までに挿入されたすべての行の挿入がロールバックされるため、ロールバックされないことです。部分的にロードされたデータで立ち往生しています。」

于 2012-03-30T15:16:18.017 に答える
0

データベースを初期化するとき、つまり一連のテーブル/ビュー/関数/トリガーなどを作成します。および/または初期データのロードでは、常にpsqlとその変数を使用してフローを制御します。私はいつも追加します:

\set ON_ERROR_STOP

スクリプトの先頭にあるので、例外が発生すると、psqlは中止されます。これはあなたの場合にも役立つようです。

また、例外処理を行う必要がある場合は、次のような匿名のコードブロックを使用します。

DO $$DECLARE _rec record;
BEGIN
FOR _rec IN SELECT * FROM schema WHERE schema_name != 'master' LOOP
    EXECUTE 'DROP SCHEMA '||_rec.schema_name||' CASCADE';
END LOOP;
EXCEPTION WHEN others THEN
NULL;
END;$$;
DROP SCHEMA master CASCADE;
于 2012-03-30T19:53:46.447 に答える