実装例
占有ロック
DB::unprepared('LOCK TABLES lock_target_table WRITE');
共有ロック
DB::unprepared('LOCK TABLES lock_target_table READ');
Eloquentのクエリビルダを使う方法は見つけられなかったので、生クエリを実行している
ダメな例
HogeHogeModel::lockForUpdate()->get();
全レコードに対してlockForUpdate()しても、テーブルロックの挙動にならなかった。
(別のトランザクションから、まだ存在しないレコードに対して占有ロック(ギャップロック )をかけることができてしまい、その後デッドロックになるリスクがある)
検証
全行ロックだと存在しない行のロックがブロックされない例
| T1 | T2 | コメント |
|---|---|---|
| BEGIN; | ||
| BEGIN; | ||
| SELECT * FROM locks FOR UPDATE; | 行全部ロック | |
| SELECT * FROM locks WHERE name="not_exist_record" FOR UPDATE; | 存在しない行のロックが取れてしまう | |
| >Empty set |
テーブルロックで存在しない行のロックがうまくブロックされる例
| T1 | T2 | コメント |
|---|---|---|
| BEGIN; | ||
| BEGIN; | ||
| LOCK TABLES locks WRITE; | テーブルロック | |
| SELECT * FROM locks WHERE name="not_exist_record" FOR UPDATE; | 存在しない行のロック | |
| ... | T1のテーブルロックが終わるまで待つ | |
| COMMIT; | ||
| >Empty set | T1のテーブルロックが終わったので実行される |
Versions
- Laravel 5.8
- MySQL 5.7