私はInnoDBテーブルで重要な更新を行ういくつかの(php)コードを持っています。MySQLで現在のトランザクションをバイパスできますか?
私は(SELECT ... FOR UPDATE)を使用していますので、トランザクション内にいる必要があります。
このコードは、データがフォームから投稿されたときに実行され、エラー/成功メッセージがデータベースに格納され、次にページがレンダリングされるときにデータベースから抽出されるようにメッセージシステムを備えています。
いくつかの擬似コード: (私はommittingてるのtry/catchブロックのようなものと、私は私の実際のコードを持っていることをエスケープ)
beginTransaction();
query("SELECT * FROM `table` WHERE id=1 FOR UPDATE");
$x=$_POST[$x];
query("UPDATE `table` SET `field` = $X");
//add other data in the db related to $X
query("INSERT INTO `othertable` (x,y,x) VALUES (......)");
//check for various errors...
$erros=0
if ($error_condition_1) {
messageSystem("Error Condition 1!")
$errors+=1;
}
if ($error_condition_2) {
messageSystem("Error Condition 2!")
$errors+=1;
}
if ($errors) {
rollBackTransaction();
} else {
commitTransaction();
}
は問題が明らかでなければなりません:messageSystemは、エラーを保存するときデータベースは後でロールバックされ、ユーザーはエラーメッセージを見ることはありません。
私が見ることができる2つの簡単な解決策があります。
- は
messageSystem
がトランザクション外で呼び出されるように自分のコードを変更します。しかし、私が上記のようにインラインで行うことができれば、それは読みやすく、速く書くことができます。また、既にネストされたトランザクション内にある可能性があるライブラリコードの場合はどうなりますか? messageSystem
を変更して、データベースとの独自の接続を使用するようにします。しかし、もし私がmessageSystemをもっと複雑にして、そのセッションにメッセージを追加する前に、session
テーブル内のエントリをロックする必要があると決めたらどうしたらいいですか?私のメインコードが何らかの理由でセッションをロックしていると、デッドロックが発生する可能性があります。- トランザクションの前にエラーをチェックしてください。しかし実際には、の前に 'FOR UPDATE' を選択して関連する行をロックする必要があります。入力を検証できます。
そして、私の質問:トランザクションがロールバックされた場合にXがとにかくコミットされるような、おそらくネストされたトランザクションの内部でXをコミットする方法はありますか?
また、私が説明した問題を回避する良い方法があります。
ありがとうございます!
ええ、それは私の現在の解決策であり、おそらく最良の賭け(+1)ですが、他の方法があるかどうか本当に知りたいと思っています。 – DaedalusFall
各接続はそれぞれの目的に合っている必要があります。つまり、トランザクションの分離が適切に機能します。別の理由でデータベースを使用する必要がある場合(この場合はログイン)、別の接続を使用するのが正しい方法です。 – mikebabcock
わかりやすく分かれていて、あなたはこの状況に合っていると思います。しかし、それがより複雑になったらどうなるでしょうか?私はすでに自分のメッセージテーブルから私のセッションテーブルへの外部キー制約を持っています(セッションが終了すると、残されたメッセージは削除されます)。上記のコード中にセッションを削除することができます。私はこれに対処することができますが、すでに分離は100%清潔ではありません。私は代替回答に興味があるので、このような良い分離がないかもしれないより複雑なシナリオでそれを扱うことができます。そんな長いコメントをおかけして申し訳ありません。 – DaedalusFall