CakePHP3: 行ロック(SELECT 〜 FOR UPDATE)

BEGIN;
SELECTFOR UPDATE; /* COMMITするまで選択した行をロック*/
UPDATE 〜;
COMMIT;

これを CakePHP3 で行うと

ConnectionManager::get('default')->transactional(function () use ($id) {
    $query = $this->TableClass;
    $query->find()->where(['id' => $id])->epilog('FOR UPDATE');
    $query->first();

    //UPDATE などの処理

});

こんな感じ

概要

ハマった事

  • Query オブジェクトは遅延評価さるので、下記のコードでは SELECT 〜 FOR UPDATE のクエリがまだ実行されておらず、ロックされない。
ConnectionManager::get('default')->transactional(function () use ($id) {
    $query->find()->where(['id' => $id])->epilog('FOR UPDATE');
  • クエリを実行する必要があるので、下記のように first() メソッド などを実行して、クエリが実行される条件を満たす必要がある。
ConnectionManager::get('default')->transactional(function () use ($id) {
    $query->find()->where(['id' => $id])->epilog('FOR UPDATE')->first();

備考

  • $this->TableClass->getConnection()->logQueries(true); のようにすると実際に実行されるSQLを確認できる