Cakeで行ロックを使う方法

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()したときの状態に戻ります。

タイトルとURLをコピーしました