- 締切済み
MySQLでのdeadlockをPHPで検出する方法
MySQLで、deadlockが発生した場合、強制的なrollbackが、どちらかのトランザクションにかけられます。 これは、当然ですし、いいんですが。 問題は、PHPでどのようにこれを検知し、再実行をかけるには、どのようなコーディングをすればいいのかということです。 データベースの取り扱いには、PEARを使っていますので、できれば、PEAR DB で扱えると嬉しいのですが。 PEAR のソースで、deadlock を探したんですが、見つからないもので。 よろしくお願いします。
- みんなの回答 (1)
- 専門家の回答
みんなの回答
- ach-sv
- ベストアンサー率0% (0/0)
>これは、当然ですし、いいんですが。 http://www2s.biglobe.ne.jp/~coach/onepoint/database/db_deadlock.html この話はあくまでこのサイトの方の言うことですが、デッドロックはバグなので設計を見直した方がよいです。 >検知し、再実行をかけるには PHPはmysql_queryが呼ばれると結果が返るまでプログラムの実行を停止するので、ここでデッドロックが発生するとPHPはタイムアウトするまで実行を停止することになります。 デフォルトの設定だとmax_execution_time < mysql.connect_timeoutなので(多分)デッドロックすると何も出来なくなります。 (set_time_limitの説明を読むとこの解釈がまちがってる可能性も考えられますが) で、検知する方法ですが単純な方法としてはクエリーの実行(もしくはトランザクション開始から終了まで)にかかった時間を測定し、mysql.connect_timeoutと比べればいいです。 mysql.connect_timeoutより実行時間が長ければロールバックしていると分かります。 ただ、アクセスが多いとクリティカルセクションが複雑に絡み合ってしまうかもしれないので、そんな状況で再実行をかけるとorz
お礼
あまり美しくはありませんが、一応の解決方法を見つけました。 デッドロックが起きると、どちらかを強制的に失敗させて、エラーオブジェクトを返します。 ここで、このエラーオブジェクトのuserInfoからdeadlockが起きたという情報を拾えます。 この間は、while で回すようにしました。 もっと、うまい方法があるといいんですが。 <?php require_once('config.php'); $con = DB::connect($dsn); $dl = true; while($dl) { $sql = "START TRANSACTION"; $con->query($sql); $sql = "SELECT * FROM xxxx FOR UPDATE"; $res = $con->query($sql); sleep(10); $sql = "UPDATE yyyy SET x = 0"; if(DB::isError($res = $con->query($sql))) { $ui = $res->userinfo; if(!preg_match('/[d|D]eadlock/', $ui)) { die('予期せぬエラー'); } else { print('Deadlock<BR>'); } } else { $dl = false; } $sql = 'COMMIT'; $con->query($sql); } ?>
補足
deadlock は、バグではありません。1つのデータベースを複数のアプリケーションで使う場合、確率的に発生する可能性があります。可能性を減らすように実装するのは当然ですが。 これは、RDBMSを使用する以上、避けて通れない問題です。 実行時間を見て、判断するというような、方法ではなく、もっと、うまい方法があるのではと期待しているのですが。