1

MySQL でデッドロックが発生し、非常にイライラしています。デッドロックが発生すると即座に発生するため、ロックのタイムアウトを超えたことが原因ではありません。デッドロックを生成する 2 つの別個のスレッド (接続プールからの 2 つの別個の接続) で実行されている SQL コードを次に示します。

UPDATE Sequences SET Counter = LAST_INSERT_ID(Counter + 1) WHERE Sequence IS NULL

Sequences テーブルには、Sequence と Counter の 2 つの列があります。

LAST_INSERT_ID により、MySQL の推奨に従って、この更新されたカウンター値を取得できます。それは私たちにとって完璧に機能しますが、これらのデッドロックが発生します! なぜそれらを取得しているのか、どうすれば回避できるのでしょうか??

これについて何か助けてくれてありがとう。

EDIT:これはすべてトランザクション内にあり(Hibernateを使用しているため必要です)、AUTO_INCREMENTはここでは意味がありません。もっとはっきり言うべきだった。Sequences テーブルには、多くのシーケンスが保持されます (この例では約 1 億個)。カウンターをインクリメントして、その値を取得する必要があります。AUTO_INCREMENT は、これらすべてにおいて何の役割も果たしません。これは、ID や PRIMARY KEY とは何の関係もありません。

4

4 に答える 4

2

SQL ステートメントをトランザクションでラップします。トランザクションを使用していない場合、LAST_INSERT_ID で競合状態が発生します。

しかし実際には、カウンタ フィールドauto_incrementが必要なので、mysql にこれを処理させます。

3 番目の解決策は、LOCK_TABLESを使用してシーケンス テーブルをロックし、他のプロセスが同時にアクセスできないようにすることです。INNODB を使用していない限り、これはおそらく最も遅いソリューションです。

于 2010-05-26T23:29:48.010 に答える
0

他のSQLは関係ありませんか? 私には少しありそうにないようです。

'where sequence is null' により、おそらく全テーブル スキャンが発生し、すべての行/ページ/... で読み取りロックが取得されます。

(特定のエンジンが MVCC を使用せず、) 同じトランザクション内で更新の前に INSERT があった場合、これは問題になります。その INSERT は、何らかのリソース (行/ページ/...) で排他ロックを取得したため、他のスレッドによる読み取りロックの取得が待機状態になります。したがって、2 つの接続が最初に挿入を行い、それぞれがテーブルの小さな部分に排他ロックを設定し、次に両方が更新を実行しようとするため、それぞれが読み取りロックを取得できる必要があります。テーブル全体。

于 2010-05-27T08:39:34.100 に答える
0

デッドロックはトランザクション データベースの通常の部分であり、いつでも発生する可能性があります。デッドロックが発生しないことを保証する確実な方法はないため、一般的に、それらを処理するアプリケーション コードを作成することになっています。そうは言っても、大規模なトランザクションの使用など、デッドロックが発生する可能性が高くなる状況があり、その発生を軽減するためにできることがあります。

まず、このマニュアルページを読んで、それらを回避する方法をよりよく理解してください。

Counter第 2 に、カウンターの更新だけを行っている場合は、「選択してから更新」プロセスに依存するのではなく、AUTO_INCREMENT 列を実際に使用する必要があります。デッドロック。基本的に、テーブル列の AUTO_INCREMENT プロパティはカウンターとして機能します。

最後に、頻繁にデッドロックが発生するため、トランザクション内に update ステートメントがあると仮定します。実際の動作を見たい場合は、ここにリストされている実験を試してください。それがまさにあなたのコードで起こっていることです... 2 つのスレッドが、そのうちの 1 つがコミットされる前に同時に同じレコードを更新しようとしています。インスタントデッドロック。

あなたの最善の解決策は、トランザクションなしでそれを行う方法を理解することです.AUTO_INCREMENTはそれを可能にします.

于 2010-05-26T23:57:56.813 に答える