ホームページ  >  記事  >  データベース  >  MySQLのデッドロックの使い方と検出・回避方法を詳しく解説

MySQLのデッドロックの使い方と検出・回避方法を詳しく解説

WBOY
WBOY転載
2022-09-09 13:43:562552ブラウズ

推奨学習: mysql ビデオ チュートリアル

ロックを使用する場合、注意が必要な問題があります。排他ロックには相互に排他的な特性があることがわかっています。トランザクションまたはスレッドがロックを保持すると、他のスレッドがロックを取得できなくなり、ブロック待ちが発生し、ループ内で待機するとデッドロックが発生する可能性があります。

この問題をいくつかの側面から分析する必要があります。1 つはロックが解放されない理由、2 つ目はロックがブロックされた場合の対処方法、3 つ目はデッドロックがどのように発生するか、およびその回避方法です。

ロックの解放とブロック

レビュー: ロックはいつ解放されますか?
トランザクションが終了します (コミット、ロールバック);
クライアント接続が切断されます。

トランザクションがロックを解放していない場合、他のトランザクションはどのくらいブロックされますか?永久に待機しますか?
そうである場合、同時アクセスが比較的多いとき、トランザクション数が多い場合必要なロックをすぐに取得できないためブロックされており、ハングすると多くのコンピュータ リソースが占有され、重大なパフォーマンス上の問題が発生し、さらにはデータベース全体に影響を及ぼします。

オンラインでのこの間違いが怖いですか?

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

MySQL には、ロックを取得するまでの待ち時間を制御するパラメータがあり、デフォルトは 50 秒です。

show VARIABLES like "innodb_lock_wait_timeout";

デッドロックの場合、いくら待ってもロックが取得できません。この場合、50秒待つ必要がありますか?その50秒は無駄ではありませんか?

デッドロックの発生と検出

デモンストレーション、2 つのセッションを開く:

タイムラインの撤回を容易にします。ここでは写真が使用されています。興味のある方は真似してください。

栗 1:

## 栗 2:

最初のトランザクションでは、デッドロックが検出され、すぐに終了しました。2 番目のトランザクションは、50 秒も待たずにロックを取得しました:

[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction

なぜ直接検出できるのでしょうか?これは、特定の条件を満たしている必要があるためです。私たちプログラマーにとって、明確な条件があるということは、判断できることを意味するため、デッドロックが発生した場合、通常、InnoDB はアルゴリズム (待機グラフ) を通じて自動的にそれを検出できます。

それでは、デッドロックが発生するにはどのような条件を満たす必要があるのでしょうか? ロック自体は相互に排他的であるため、デッドロックが発生する条件は次のとおりです:

    (1)同時に、このロックを保持しているトランザクションが存在するだけです;
  • (2) このトランザクションがロックを取得できるようになる前に、他のトランザクションがロックを解放する必要があり、ロックを強制的に剥奪することはできません;
  • ( 3) 複数のトランザクションが待ちループを形成すると、デッドロックが発生します。
その理髪店にはディレクターが 2 人います。髪を切る担当のトニー先生と髪を洗う担当のケルビン先生がいます。トニー先生は同時に 2 人の人の髪を切ることはできません。これを相互排除といいます。

トニーが誰かの髪を切っているとき、彼に立ち止まって髪を切るように頼むことはできません。これを 無理に奪うことはできません

といいます。

トニーのクライアントがケルビンに言った場合: あなたが洗ってくれないなら、どうやって髪を切ることができますか? ケルビンのクライアントがトニーに言った場合: あなたが髪を切らないなら、どうやって髪を洗えますか? これは呼ばれます 待機ループを形成します。
実際にはデッドロックが発生する状況は数多くありますが、それらはすべて上記の 3 つの条件を満たしています。 これは、テーブル ロックのリソースが一度にすべて取得されるため テーブル ロックによってデッドロックが発生しない理由でもあります。

ロックが解放されていない場合、大量のブロッキングやデッドロックが発生し、システムのスループットが低下する可能性があるため、どのトランザクションがロックを保持しているかを確認する必要があります。 ロック情報の表示 (ログ)

まず、SHow STATUS コマンドには行ロック情報が含まれています:

show status like 'innodb_row_lock_%';

##lnnodb_row_lock_current_waits: 現在待機しているロックの数;

lnnodb_row_lock_time: システムの起動から現在のロックまでの合計時間 (ミリ秒単位); Innodb_row_lock_time_avg: 毎回の待機に費やされる平均時間。

Innodb_row_lock_time_max: システムの起動から現在までの最長待機時間;
lnnodb_row_lock_waits: システムの起動から現在までの待機の合計数。



SHOW コマンドは概要情報です。 InnoDB には、トランザクションとロックを分析するための 3 つのテーブルも用意されています:

select * from information_schema.INNODB_TRX; --当前运行的所有事务﹐还有具体的语句

select* from information_schema.INNODB_LOCKS; --当前出现的锁

select * from information_schema.INNODB_LOCK_WAITS; --锁等待的对应关系

更加详细的锁信息,开启标准监控和锁监控:

额外的监控肯定会消耗额外的性能

set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;

通过分析锁日志,找出持有锁的事务之后呢?
如果一个事务长时间持有锁不释放,可以kill事务对应的线程ID,也就是INNODB_TRX表中的trx_mysql_thread_id,例如执行kill 4,kill 7, kill 8。
当然,死锁的问题不能每次都靠kill线程来解决,这是治标不治本的行为。我们应该尽量在应用端,也就是在编码的过程中避免。
有哪些可以避免死锁的方法呢?

死锁的避免

  • 1、在程序中,操作多张表时,尽量以相同的顺序来访问(避免形成等待环路)
  • 2、批量操作单张表数据的时候,先对数据进行排序(避免形成等待环路);
  • 3、申请足够级别的锁,如果要操作数据,就申请排它锁;
  • 4、尽量使用索引访问数据,避免没有where条件的操作,避免锁表;
  • 5、如果可以,大事务化成小事务;
  • 6、使用等值查询而不是范围查询查询数据,命中记录,避免间隙锁对并发的影响。

推荐学习:mysql视频教程

以上がMySQLのデッドロックの使い方と検出・回避方法を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjb51.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。