【MySQL】ロックとデッドロックについて

データベース

ロックとデッドロックについて紹介します。

ロックとは

ロックとは、データを更新する前に行やテーブルを他のセッションから更新されないようにすることです。

行をロックする行ロックやテーブルをロックするテーブルロックがあります。

流れは、たとえばレコード1に対してデータを更新したいとします。
そのときに、まずはロックを取得します。
ロックされると、他のセッションからではレコード1は更新できない状態になります。
ロックを取得したら、updateで更新して完了すると、ロックを解除します。
ロックが解除されれば、他のセッションからも更新可能な状態になります。

トランザクションを使用したときのロックでは、commitやrollbackされたときにロックが解除となります。

デッドロックとは

デッドロックは、複数セッションがそれぞれロック解除待ちをしてしまって処理が完了しない状態です。

  1. たとえば、セッションAとセッションBがあり、セッションAからレコード1をupdateをする際、
    レコード1をロックします。
  2. 同じ時刻にセッションBからレコード2に対してupdateする際、
    レコード2をロックします。
  3. そして、セッションAでレコード2のupdateをしようとしたとき、
    セッションBですでにレコード2はロックされている状態のため、
    セッションAからロックを取得できない状態になります。ロック待ちの状態となります。
  4. そして、セッションBからレコード1のupdateをしようとしたとき、
    レコード1がセッションAがロックしているのでロック待ちの状態になります。
  5. セッションAもBも互いにロック待ちの状態になってしまいます。

これをデッドロックといいます。

Lock wait timeout exceeded.

これは、デッドロックが発生して、その待ち時間を超過したときのメッセージとなります。

Deadlock found when trying to get lock

これは、デッドロックが発生したというメッセージです。

lock解除待ちの確認方法

-- lock解除待ちの確認 MySQL8.0より前
select * from information_schema.innodb_lock_waits;
-- lock解除待ちの確認 MySQL8.0以降
select * from performance_schema.data_lock_waits;

デッドロックの確認方法

-- deadlockの確認
show engine innodb status;

上のコマンドを実行すると、Statusの項目に最近発生したデッドロックの情報が記載されているのが確認できます。
長いので、コピーして、メモ帳などに貼り付けると確認しやすくなります。
「LATEST DETECTED DEADLOCK」という項目に、thread idや、デッドロックが発生したSQLを確認することができます。