CakePHP4系で行ロックを使う方法です。
あんまり指摘している記事がなかったので書いてみました。
具体的にはFOR UPDATEを使うのですが、どうやって呼ぶのか?
早速コードを見てみましょう
//Tableクラス内などで use Cake\Datasource\ConnectionManager; //ロックをしたいメソッド内で $connection = ConnectionManager::get('default'); $connection->begin(); //ここで条件に合った行にロックがかかります $hoges = $this->find()->where([適当な条件])->modifier('SQL_NO_CACHE')->epilog('FOR UPDATE')->all(); foreach($hoges as $hoge){ //ここで読みこみながら更新処理をする if(エラー){ //何かエラーが発生して中止したい場合 $connection->rollback(); return ; } } //正常終了 ロック解除 $connection->commit();
ポイント
まず、ロックをかけるにはトランザクションが必要です。
ConnectionManagerを使ってコネクションオブジェクトを生成して、コネクションオブジェクトからbigin()を行いましょう。
次に、データの読み込みを行うわけですが
modifier(‘SQL_NO_CACHE’)->epilog(‘FOR UPDATE’)
の部分がポイントです。
SQL_NO_CACHEについては、キャッシュを使わずに読みこむ指示になります。使っていなくても将来的に使うかもしれませんので、一応入れておいた方がいいと思います。
肝心のFOR UPDATEの部分はepilog()メソッドで行います。
あと、はまりそうなポイントとしては、最後のall();の部分。
クエリビルダ―でall()とかfirst()とかがないとクエリーが発行されない=ロックがかかりません。
サンプルコードの場合は、all()が無くても次のforeach()文でクエリーが発行されるのであってもなくてもどっちでもいいですが、場合によっては注意したほうがいいかもしれません。
また、トランザクションなので、最後にcommit()するのを忘れずに。また、何か問題が発生してなかったことにしたい場合は、rollback()をしましょう。bigin()したときの状態に戻ります。