【MySQL】ロックとは?共有ロック,排他ロックの違いや行ロックの種類を解説

こんにちは、ほろよい(@horoyoi_blog)です

今回は MySQLのロック について解説していきます

対象は プログラミング初心者 です

簡潔に分かりやすく書いてくので是非最後まで読んで頂ければと思います

良ければSNSでシェアしてもらえると嬉しいです

それではいきましょう!

データベースのロックとは何か?

一言で言えば データの整合性を保つための仕組み です

ロックの仕組みがないと、データが意図した通りに入らないことがあります

引用元: https://www.teradata-jp.com/post/col05i

ちなみにロックの仕組みはMySQLに限らずRDBMSには基本的に備わっています

ロックの種類

ロックの種類には 行ロック テーブルロック の2種類があります

(自分はテーブルロックを意識して使ったことがないので、この記事では行ロックについて書いていきます)

更にそれぞれ排他ロック共有ロックの2種類があります

共有ロックとは

他のトランザクションがデータを書き込むことを許さないロックです

例) SELECT ~ LOCK IN SHARE MODE文

排他ロックとは

他のトランザクションがデータを読み取ることも書き込むことも許さないロックです

例) INSERT文, UPDATE文, DELETE文, SELECT ~ FOR UPDATE文

図で表すとこのような感じです

T1はトランザクション1、T2はトランザクション2を意味しています

排他ロックと共有ロックの競合を表にすると以下のようになります

排他ロック共有ロック
排他ロック競合する競合する
共有ロック競合する競合しない

続いてMySQL独自のロック方式を解説します

MySQLのロック方式

MySQLには独自のロックのかけ方があります

  • レコードロック
  • ネクストキーロック
  • ギャップロック

それぞれ簡単に解説します

解説では以下のテーブルを使います

idname
1satou
2suzuki
3takahashi
4matui
7katou

また、トランザクションの分離レベルはMySQLのデフォルトである REPEATABLE READ を想定しています

レコードロック

以下のようなUPDATE文があった場合、id=1 のレコードがロックされるのは分かると思います

UPDATE users SET name = horoyoi WHERE id = 1 ;

これをレコードロックと呼びます

ネクストキーロック

では次の場合はどうでしょうか?

SELECT * FROM users WHERE id BETWEEN 1 AND 3 FOR UPDATE;

この場合は idが1, 2, 3, 4 の全部で4行がロックされます

4も入ることを疑問に感じるかもしれませんが、入ります

なぜならMySQLでは走査したインデックスレコード全てをロックするからです

このロックがネクストキーロックと呼ばれています

(インデックスレコードって何…という方もいると思うので、インデックスの知見をまとめた記事も今度書く予定です。とりあえず今はこういうロックもあるんだなーぐらいの理解でOKです)

ギャップロック

お次はこちら

SELECT * FROM users WHERE id = 5 FOR UPDATE;

今回のテーブルでは idが5 のレコードは存在しません

この場合は 4 と 7 の間のスペースがロックされます

例えば、このSQLを実行中に 他のトランザクションから 

INSERT INTO users values (id: 4, name: horoyoi); 

のようなSQLを実行するとロック解放待ちとなり、SELECT ~ FOR UPDATE のクエリがコミットされるまで、インサートできません

このようなロックをギャップロックと呼びます

ここまで紹介して分かる通り、mysqlでは対象のレコード以外にもロックをかける可能性があることに注意してください

デッドロックが起きた時や更新系クエリがいつまでも待たされてしまうような時には想定外の行にロックがかかっていないかを疑いましょう

厳密に言うとロックの範囲はトランザクションの分離レベルによっても変わってくるのですが、初学者の場合はここまでで十分だと思います

まとめ

今回はMySQLのロックの基礎を簡単に解説してみました

この記事が初心者の方のお役に立てたら幸いです

良かったらTwitterもフォローしてもらえると嬉しいです

ではでは( ̄  ̄)ノ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です