Postgresのトランザクションについて調べると、トランザクションを開始
した場合、ロールバック、もしくはコミットをするか、設定値の時間が
経過しないとトランザクションは終了しない。となっていました。
確かに、コンソール上で、Postgresを操作すると、上記のような動作に
なっていることを確認しましたが、PHPのスクリプト上でトランザクションを
実行すると、少し違う動きをするようでした。
例えば、下記のような場合、exitした時点でトランザクションが終了していました。
本来であれば、exitする前にロールバックする処理をいれるべきなのかと思いましたが
この場合は特になにもしないでよいのでしょうか。
---
$mdb2->beginTransaction();
$sql = "SELECT * FROM test WHERE id = ? FOR UPDATE";
$res = $mdb2->execute(array("100"));
$status = $res->fetchOne("status");
// ↓エラーが起きた場合。ここにロールバックする処理は入れない?
if (!$status) {
header("Location: http://errorerrorerror")
exit;
}
// ここにtestテーブルをUPDATEする処理など
$mdb2->commit();
?>
皆さんはどうされているのか知りたくて質問しました。
よろしくお願いします。
もう御自身で納得されておるようですが参考になるかと思い回答させていただきます。
私は癖としてコミットとロールバックは必ず書くようにしています。
今回の場合はPDOというライブラリはクローズ時のデフォルトの挙動がロールバックになっていることとSQLが検索だけだったため特に問題はありません。
ですがデフォルトの処理を当てにする癖をつけていると以下のような場合に問題に遭遇する可能性があります。
・別のライブラリや言語を使った場合に嵌まる可能性がある
・処理が長くなりソースを分割した場合にSQL文とコネクションをクローズするところが離れていて更新系のSQLだということに気がつかない可能性
・DBによってはクローズ時に自動でコミットするものがある
明にコミットもしくはロールバックの処理が書かれていないソースを見ると何かおかしいと思うようにしておいた方が良かろうかと思います。
$mdb2->beginTransaction();
このように明示的にトランザクションの開始を宣言する
プログラムスタイルでは
通常は、コミットもロールバックもきちんと書くのが普通です。
設定によっては、トランザクションの開始を書かなくて良い場合があり
その場合は、コミットの時だけ明示的に書き、ロールバックの場合は書かないという
スタイルが多いです。
>その場合、!empty($mdb2) && $mdb2->isTransaction()のようにすることで、簡易的?
MDBオブジェクトを生成してるかどうかの判断は必要だと思いますが、
トランザクションを開始していない状態で
ロールバックをしても、問題ないはずですけどね。
トランザクションが開始されてるかどうかのチェックのが普通だとは思えないです。
トランザクション宣言しているのであれば、正常系ではコミットを、異常系ではロールバックすべきです。
ご質問にあるソースでは、exit() する前にロールバック処理を入れましょう。
回答ありがとうございます。
2012/04/27 05:48:19やはり、自動でロールバックされるとはいえ、明示的にスクリプト内でロールバック
させた方がぐっすり眠れそうですね。
ただ、現在PEAR MDB2を使ってDBを操作していますが、エラーの処理をエラーハンドラ
関数を指定してまとめて行なっています。
その関数内でMDB2オブジェクトをグローバル宣言することで、トランザクション中か
確認できますが、MDBオブジェクトを生成していない場合でも、この関数を通る場合
があります。
その場合、!empty($mdb2) && $mdb2->isTransaction()のようにすることで、簡易的?
にデータベースに接続済みなのか判定できますが、より正確な判断ができないものかと
悩みます。