これはPDOのせいではなく、PostgreSQLのトランザクション管理に固有のものです。参照:
- 単一の制約が失敗したときにトランザクション全体を中止しないようにPostgreSQLに指示するにはどうすればよいですか?
- Postgresqlにトランザクション内のエラーを無視するように依頼できますか
- トランザクションエラー後のロールバック
PostgreSQLはトランザクションをロールバックしませんが、ロールバックのみが可能で、ROLLBACK
を除くすべてのステートメントが終了した状態にトランザクションを設定します。 エラーを報告する:
(これが公式ドキュメントで参照されていないことに驚いています。それを改善するためにパッチを作成する必要があると思います。)
そう。 PDOで例外を試行/キャッチして飲み込むと、PHP側の例外がトラップされますが、PostgreSQLトランザクションが中止された状態にあるという事実は変わりません。
例外を飲み込んでトランザクションを使い続けることができるようにするには、 SAVEPOINT
を作成します
失敗する可能性のある各ステートメントの前。失敗した場合は、ROLLBACK TO SAVEPOINT ...;
する必要があります。 。成功した場合は、RELEASE SAVEPOINT ...;
を使用できます。 。これにより、トランザクション管理のためにデータベースに余分なオーバーヘッドがかかり、ラウンドトリップが追加され、トランザクションIDの書き込みが速くなります(つまり、PostgreSQLはより多くのバックグラウンドクリーンアップ作業を行う必要があります)。
通常の状況で失敗しないように、代わりにSQLを設計することをお勧めします。たとえば、ほとんどの制約をクライアント側で検証し、サーバー側の制約を第2レベルの保証として扱い、ほとんどのエラーをクライアント側でトラップできます。
それが実用的でない場合は、アプリケーションをフォールトトレラントにして、失敗したトランザクションを再試行できるようにします。とにかくこれが必要な場合もあります。たとえば、通常、セーブポイントを使用して、デッドロックトランザクションの中止やシリアル化の失敗から回復することはできません。また、障害が発生しやすいトランザクションをできるだけ短くして、必要な最小限の作業を実行することも役立ちます。これにより、追跡して繰り返す必要が少なくなります。
したがって、可能な場合は、例外を飲み込む代わりに、失敗しやすいデータベースコードを再試行ループで実行します。コードが、最新のステートメントだけでなく、エラー時にトランザクション全体を再試行するために必要な情報の記録を保持していることを確認してください。
任意を忘れないでください トランザクションが失敗する可能性があります。DBAがデータベースを再起動してパッチを適用したり、cronジョブが暴走したためにシステムのRAMが不足したりする可能性があります。したがって、障害耐性のあるアプリはとにかく優れた設計です。
少なくともPDO例外を使用し、例外を処理するための小道具-あなたはすでにほとんどの開発者よりもはるかに進んでいます。