PHP:ロールバックしているはずがロールバックされない
これまでに見たことがあるバグです。
あるシステムで、
- 入力内容をデータベースに登録処理
- 決済処理
- メール送信処理
という流れで処理をしていました。
決済処理でエラーが発生した場合とは、例えばクレジットカード番号が間違っていて決済できなかったときが該当します。
決済処理でエラーが発生しすると、データベースに登録のトランザクションをロールバックして、登録した内容を破棄しています。
あるシステムで決済処理でエラーを起こしてデータベースを確認すると、破棄しているはずのデータがデータベースに登録されています。
pq_queryの使い方の違い
プログラムを見ると、以下のような構成になっていました。
$conn = pg_pconnect("dbname=publisher"); // トランザクション開始 pq_query("BEGIN"); // データベース登録処理 pq_query($conn, 'INSERT INTO table1 (email) VALUES ('example@com')); // 決済処理 // 省略 if (決済処理の結果 == エラー) { // 決済処理でエラー pq_query("ROLLBACK"); } else { // 決済処理で正常 pq_query("COMMIT"); }
これでどうしてデータベースにデータが登録されるのかと悩みだしました。
PHP: pg_query - Manual
のマニュアルを見ながら考えていると、トランザクション関係のpg_query()の第1引数が省略されているのが気になりました。
第1引数は、
connection PostgreSQL データベース接続リソース。connection が指定されていない場合はデフォルトの接続が使用されます。 デフォルトの接続は、直近の pg_connect() あるいは pg_pconnect() によって作成されたものです。
と書かれているので、省略しても同じ接続リソースを使っているように見えます。
注意: connectionは省略可能ですが、それは推奨されません。 なぜならスクリプトのバグが発見しにくくなるためです。
とも書かれている点が気になった点です。
気になったら試してみるのがはっきりするので、トランザクション関係のpg_query()の第1引数を指定したところ、トランザクションをロールバックできるようになりました。
トランザクション関係のpg_query()の第1引数を省略していたことが原因でした。
省略していても、PHPの実行を止めるような致命的なエラーが発生していなかったので、気づくまで時間がかかりました。