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


18

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

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

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

回答:


13

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

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

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

そうでなければ、この時点で他の合理的な解決策はありません。


13

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

警告:進行中のトランザクションが既にあります

ネストされたトランザクションはPostgreSQLに実装されていないため、新しい(サブ)トランザクションは開始されません。(pl/pgsqlただし、たとえば、その振る舞いを模倣するような関数で魔法をかけることができます。)

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

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


9

PostgreSQLはサブトランザクションをサポートしていませんが、このSAVEPOINT機能はニーズに効果的に応えることができます。GitHubのVitaly Tomilovによる約束介した、PGへのAdvanced access layerのドキュメントからの引用:

PostgreSQLは、ネストされたトランザクションを適切にサポートしていません。トランザクション内のセーブポイントを介した部分的なロールバックのみをサポートしています。さらに説明したように、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ドキュメントを参照してください。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.