1

次の例外に直面しています:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

私が言えることは、複数のスレッドが同じテーブルに対して並行してクエリを実行していることです。しかし、なぜこの例外が発生するのか理解できません。あるクエリがテーブルをロックした場合、別のスレッドの同じクエリ (または同じテーブルの他のクエリ) がロックを待機するためです。デッドロックが発生するのはなぜですか?

別の言葉で繰り返しますが、例外は理解していますが、理解できないのは、クエリが他のクエリを待機しており、他のクエリが実行され、ロックを離れ、待機中のクエリがロックを取得できるということです。なぜデッドロックなのですか?

誰かが実際のクエリを見たい場合 (これらのクエリは、トランザクションなしで、ここに印刷されているのと同じ順序で複数のスレッドで実行されます):

UPDATE daily_stats, account, campaign SET campaign_messages_cost = campaign_messages_cost + (IF(current_free_sms >= ?, campaign.campaign_cost, campaign.campaign_cost + (account.sms_charging_rate * ? ))), campaign_messages_delivered_count = campaign_messages_delivered_count + 1 WHERE daily_stats_id = ? AND campaign.id = ? AND daily_stats.account_id = account.id

update account a JOIN campaign b ON a.id = b.account_id set campaign_cost = IF(current_free_sms >= ?, campaign_cost, campaign_cost + (a.sms_charging_rate * ? )), delivered_count = delivered_count + ?, credit = IF(current_free_sms >= ?, credit, credit - (a.sms_charging_rate * ?)), current_free_sms = IF (current_free_sms >= ?, current_free_sms - ?, current_free_sms) where b.id = ?
4

1 に答える 1

1

MySQL はすべてのクエリ ステートメントをトランザクションと見なします (少なくともデフォルトの InnoDB エンジンを使用している場合) が、@@autocommit 変数が 1 (デフォルト) に設定されている場合、すべてのステートメントはすぐに自動コミットされ、トランザクションが発生したことが事実上隠蔽されます。エラーメッセージの「ロールバック」部分はやや不可解であり、以前に見たものは何もありませんが、これは、開始/コミット/ロールバックがないにもかかわらず「デッドロックが見つかりました」エラーを説明できます。

MySQL が提案するデッドロックの処理方法は、クエリを構造化して問題を最小限に抑えることと、問題が発生したときにそれらを処理するコードを記述することの組み合わせです。私の方法は単純ですが効率的です。500 ミリ秒スリープしてから再試行します。かなり高い負荷を処理するシステム (企業環境ではありますが) で、2 回以上連続して再試行することはめったにありません。

デッドロックに対処する方法については、MySQL の推奨事項も確認してください。

于 2013-04-04T12:26:32.060 に答える