web-dev-qa-db-ja.com

トランザクション内のトランザクション

たとえば以下のスクリプトが呼び出された場合、PostgreSQLはどのような動作を表示しますか

BEGIN;
SELECT * FROM foo;
INSERT INTO foo(name) VALUES ('bar');
BEGIN; <- The point of interest
END;

PostgreSQLは2番目のBEGINを破棄しますか、それとも暗黙的にコミットが決定され、最後にBEGINENDブロックを別のトランザクションとして実行しますか?

19
Alex

必要なのは、いわゆる「自律型トランザクション」(Oracleが提供する機能)です。現時点では、これはPostgreSQLではまだ可能ではありません。ただし、 [〜#〜] savepoint [〜#〜] sを使用できます。

BEGIN;
INSERT ...
SAVEPOINT a;
some error;
ROLLBACK TO SAVEPOINT a;
COMMIT;

これは完全に自律的なトランザクションではありませんが、「すべてのトランザクション」を正しく行うことができます。これを使用して、自律型トランザクションに期待することを実現できます。

それ以外の場合、現時点では他の適切な解決策はありません。

14

あなたはそれを自分で試すことができます:

警告:すでにトランザクションが進行中です

ネストされたトランザクションはPostgreSQLに実装されていないため、新しい(サブ)トランザクションは開始されません。 (pl/pgsql関数、たとえば、その動作を模倣します。)

PostgreSQL 11では、新しい実際のストアドプロシージャとトランザクションを処理するその機能により、ネストされたトランザクションが可能になると考えることができます。ただし、 documentation によると、これは当てはまりません。

CALLコマンドによって呼び出されるプロシージャ、および匿名コードブロック(DOコマンド)では、COMMITおよびROLLBACKコマンドを使用してトランザクションを終了できます。これらのコマンドを使用してトランザクションが終了すると、新しいトランザクションが自動的に開始されるため、個別のSTART TRANSACTIONコマンドはありません。

13
dezso

PostgreSQLはサブトランザクションをサポートしていませんが、SAVEPOINT機能は効果的にニーズに応えることができます。 GitHubの Promiseを介したPGへの高度なアクセスレイヤー のドキュメントからの引用 Vitaly Tomilov による:

PostgreSQLはネストされたトランザクションを適切にサポートしていません。トランザクション内の savepoints を介した部分的なロールバックのみをサポートしています。さらに説明するように、2つの手法の違いは非常に大きくなります。

ネストされたトランザクションの適切なサポートとは、親トランザクションがロールバックされても、成功したサブトランザクションの結果はロールバックされないことを意味します。ただし、PostgreSQLセーブポイントでは、トップレベルのトランザクションをロールバックすると、すべての内部セーブポイントの結果もロールバックされます。

セーブポイントは、アクティブなトランザクション内の以前のポイントへの部分的なロールバックに使用できます。たとえば、セーブポイントを確立し、確立後に実行されたすべてのコマンドの影響を後で取り消すには、次のようにします。

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

上記のトランザクションは、値1と3を挿入しますが、2は挿入しません。詳細については、 SAVEPOINT のドキュメントを参照してください。

9
Amir Ali Akbari

Postgresql 9.5以降では、pg_background拡張によって提供される動的なバックグラウンドワーカーを使用できます。自律型トランザクションを作成します。拡張機能の githubページ を参照してください。ソリューションはdb_linkより優れています。 PostgreSQLの 自律型トランザクションサポートに関する完全なガイドがあります

0
shcherbak