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のドキュメントもチェックする必要がありそうです。