DBのロックの種類
DBのロックには、大きく以下の2種類があります。
- 共有ロック
- 排他(占有)ロック
共有ロックとは、参照はできるけど、更新はさせないロック。
排他ロックとは、参照も更新もさせないロック。
そしてロックする対象についても、大きく以下の2種類がある。
- テーブルロック
- 行ロック
テーブルロックとは、そのテーブルに対してロックをかけること。
行ロックとは、そのレコードに対してロックをかけること。
正確には、DBロックもありますが、DBに対してロックをかけるという、あまり一般的ではないロック手法なので割愛します!
つまり…
usersテーブルに対して排他ロックをかけている状態というのは…
セッションAがusersテーブルに対してアクセスしてから、
セッションBもusersテーブルに対してアクセスしようとすると、
セッションAのusersテーブルに対するアクセスが終わるまで、
セッションBはusersテーブルの参照もできず、待たされるということです。
この、待たせるのか、速攻エラーにするのかで、悲観的ロックなのか、楽観的ロックなのかという呼び分けもできます。
普段アプリケーション開発をしていて、テーブルロックされるとデッドロックにも繋がりやすいし、
なかなか厳しいわけです。
なので、テーブルロックではなく、できるだけ行ロックになるようにコードを書きましょう!
具体的にどうするのかというと…
行ロックになるようにする方法
「あるレコードを更新したい!」となり、whereで絞り込む際、
できるだけプライマリーキーもしくはユニークキーで絞り込むようにしましょう。
例えば、usersテーブルには、以下のカラムがあったとします。
- ID id(プライマリーキー)
- マイナンバー my_number(ユニークキー)
- 名前 name
usersを絞り込む時に、users.where(id: 1)と絞り込むと、user.idが1のレコードに対して、
行ロックがかかります。
これはプライマリーキーで絞り込むと、MySQLが自動で「行ロックだ!」となってくれるわけです。
ユニークキーも同様です。
users.where(my_number: ‘123456’)で絞り込むと、my_numberが’123456’のレコードに対して、
行ロックがかかります。
裏を返すと、プライマリーキーまたはユニークキーで絞り込まない場合、
テーブルロックになってしまいます。
users.where(name: ‘鈴木’)で絞り込むと、usersテーブル自体に対して、テーブルロックがかかってしまい、
アクセスを待たせてしまうセッションが多くなってしまうわけです。