実装例
占有ロック
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