3

PostgreSQL9.0データベースを変更するために.NET4.0でNpgsql2.0.11を使用しています。プログラムは、すべて1つのトランザクション内で、データベースに多くの変更を加えます。

コミットする直前に、SELECTステートメントを実行しますが、失敗することがあります(タイムアウトなど)。私は例外を飲み込み、先に進んでとにかくトランザクションをコミットします。エラーはないので、すべてが機能しているように見えますが、実際にはデータベースはまったく変更されていません。

私の推測では、失敗したSELECTはトランザクション全体をロールバックしました。これを防ぐ(つまり、トランザクションをまだコミットする)か、少なくともこの状況を検出して例外をスローし、ユーザーがコミットが失敗したことを認識できるようにすることはできますか?

この特定のケースでは、SELECTをトランザクションの外に移動できることは知っていますが、一般的なケースではこれを解決することに関心があります。コミットをコミットしないことはかなり深刻な問題であり、それが検出されないようにしないようにしたいと思います。

4

3 に答える 3

7

Npgsqlについては何も知りませんが、PostgreSQLの動作について話すことができます。PostgreSQLトランザクション内でエラーが発生すると、トランザクションは閉じられるまで無効としてマークされます。(それらの用語は「中止」であり、誤解を招くと思います。)さらに、これはIMHOの非常識ですCOMMIT。無効なトランザクションの場合、「成功」しますが、と同じ効果がありROLLBACKます。これはpsqlREPLで確認できます。ROLLBACKコマンドに応じて出力されますCOMMITが、エラーは通知されません。

SAVEPOINTファイナルの直前に作成できますSELECT。失敗した場合はROLLBACK、セーブポイント名に移動します。これにより、無効な状態から抜け出し、トランザクションの前の部分をコミットできるようになります。

于 2011-09-23T19:02:00.773 に答える
0

コミットする直前に、トランザクションの一部として簡単なステートメントを実行しようとする小さなラッパーメソッドを作成することになりました。これは、問題の検出に効果的です。

    public static void CommitTransaction(NpgsqlConnection conn, NpgsqlTransaction tran)
    {
        using (var command = new NpgsqlCommand("SELECT 1", conn, tran))
        {
            try
            {
                command.ExecuteScalar();
            }
            catch (NpgsqlException ex)
            {
                if (ex.Code == "25P02")
                    throw new Exception("The transaction is invalid...");
                throw;
            }
        }

        tran.Commit();
    }

修正はMorgのいずれかです。またはRyanCulpepperの回答:トランザクションの外部でステートメントを実行するか、事前にSAVEPOINTを作成して、エラーが発生したときにロールバックします。

于 2011-09-24T00:42:00.717 に答える
-1

トランザクション内で何かが失敗しても、トランザクションが完了することは、トランザクションの権利ではありませんか?

したがって、基本的に、失敗する可能性があり、気にしない場合は、失敗してはならないトランザクションに入れないでください。

トランザクションは使用するためのものであり、問​​題は発生しないため、トランザクションを使用してください;)

于 2011-09-23T12:37:41.293 に答える