2012-01-11 4 views
1

ユーザーの勘定残高を保持するフィールドがユーザーテーブルにあります。ユーザーは自分のサービスで多くのアクションを実行することができ、その結果、バランスが急速に変化します。mysqlによる勘定残高の更新

私は、複数のユーザアクションが値を間違って更新しないようにするために、シリアライズ可能なアイソレーションレベルを使用しようとしています。 (アクションAとアクションBは同時に天びんから1ドルを差し引きたいと思っています。)しかし、デッドロック・エラーが多く発生しています。

これらのデッドロックをすべて取得せずに残高フィールドを最新の状態に保つことなく、正しく行うにはどうすればよいですか?

シンプルなスキーマ:ユーザーにはIDと残高があります。

教義を使用してイムので、私は、次のようなものをやっている:あなたのトランザクションにシリアライズ可能な分離レベルを使用しようとして

$con->beginTransaction(); 
$tx = $con->transaction; 
$tx->setIsolation('SERIALIZABLE'); 

$user = UserTable::getInstance()->find($userId); 
$user->setBalance($user->getBalance() + $change); 
$user->save(); 
$con->commit(); 
+2

スキーマを提供し、選択、更新、すべてがトランザクション的に行われるパターンへのアクセスを提供した場合は、問題に対処する方が簡単です。 – atxdba

+0

が更新しました。 –

答えて

0

ファーストは良いアイデアです。これは、少なくとも変換が何であるかを知ることを意味し、分離レベルは最大の問題の1つです。

シリアライズ可能であることは、実際には本当のサーリーアビリティではないことに注意してください。 this previous answerの詳細については、読んでみるとよいでしょう:-)。

しかし、最も重要な点は、シリアル化が失敗したためにトランザクションに自動ロールバックがあることは通常の事実であることを考慮する必要があり、トランザクションが失敗して再生されるようにアプリケーションを構築することです。

私はこの単純な解決策が好きです。私たちはすべての事実を予測できるので、驚きはありません。テーブルロックを実行することです。これは上級で洗練されたソリューションではなく、行レベルのロックもなく、シンプルな大きなテーブルロック(常に同じ順序)です。その後、あなたは1人のプレイヤーとして操作を行い、次にロックを解放することができます。テーブルの行に複数のユーザ並行性があるわけではなく、次の行のマジカルロックは失敗しません(前のリンクを参照)。これにより書き込み操作は確実に遅くなりますが、誰でも同じ順序でテーブルロックを実行すると、ロックタイムアウトの問題、デッドロックの発生、および「シリアル化不可能な自動ロールバック」が発生しません。あなたのコードサンプルから

編集は、私はあなたが始める後にトランザクション分離レベルを設定することができますかわかりません。 MySQLでクエリログを有効にして、完了したら、CMSによって実行されている他のトランザクションがまだシリアル化可能レベルにないことを確認する必要があります。

関連する問題