Symfony(Doctrine)で排他制御を実装する

こんにちは。木戸です。

今回はSymfonyで排他制御を実装したので、実装手順をご紹介します。

排他制御とは

排他制御についてはこちらの記事に分かりやすく書かれています。

環境

Symfony5.4 
ORM Doctrine
データベース MYSQL

排他制御の導入手順

今回は排他制御で楽観ロックを行います。
Doctrineにロック機能があるので、そちらを使います。

手順1 排他制御を行いたいテーブルのカラムにバージョンプロパティを追加

User.orm.yaml


User:
  type: entity
  fields:
    version:
      type: integer
      version: true

手順2 バージョンをpostするためにtwigにインプットを記載

User/form.html.twig


 <input  name="version" type="hidden" value="{{ user.version }} >

手順3 データ更新時にロックメソッドを使用

UserController.php


use Doctrine\DBAL\LockMode;
use Doctrine\ORM\OptimisticLockException;

$entity = $em->find('User', $theEntityId);

try {
    // 手順2でtwigに記載したinputからversionの値を取得
    $version = $request->get('version') ? (int)$request->get('version'): null;
    if($version){
        $em->lock($entity, LockMode::OPTIMISTIC, $version);
    }
    $em->lock($entity, LockMode::OPTIMISTIC, $expectedVersion);
} catch(OptimisticLockException $e) {
    throw new \Exception('申し訳ありませんが、編集中に他のユーザーによる更新が行われました。最新の状態を確認してください。');
}

$em->lock()の際に、DB上のバージョンの値とpostされてきた値に差があると、OptimisticLockException()が発火します。
そのため、try {} catchで囲んでおき、編集中に他のユーザーから更新があったかを検知することが出来ます。

まとめ

Entity Managerのlockメソッドを使うことで、排他制御を実装することが出来ました。
Symfonyのドキュメントでは排他制御がヒットしなかったので、1から実装しないといけないと思っていましたが、Doctrineのドキュメントに記載がありました。
データの操作をしたいときは、Symfonyだけでなく、Doctrineのドキュメントもチェックする必要がありそうです。