Doctrine实体保存时如何注册自定义更新查询替代默认逻辑
解决方案
别上来就覆写核心EntityPersister,维护成本极高,两种适配方案按维护成本从低到高选:
方案1:微秒时间类型+事件监听(推荐)
完全兼容Doctrine内置乐观锁逻辑,不需要改动核心持久化流程:
- 先自定义支持微秒精度的DBAL时间类型,代码如下:
<?php namespace App\DBAL\Types; use Doctrine\DBAL\Types\DateTimeType; use Doctrine\DBAL\Platforms\AbstractPlatform; class DateTimeMicrosecondType extends DateTimeType { public function convertToDatabaseValue($value, AbstractPlatform $platform) { return $value === null ? null : $value->format('Y-m-d H:i:s.u'); } public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof \DateTimeInterface) { return $value; } return \DateTime::createFromFormat('Y-m-d H:i:s.u', $value); } public function getName(): string { return 'datetime_micro'; } }
- 在Doctrine配置中注册该自定义类型,将对应实体的
modified_at字段类型改为datetime_micro,同时标记为乐观锁版本字段:
// 实体映射配置示例 #[ORM\Column(type: 'datetime_micro')] #[ORM\Version] private ?\DateTimeInterface $modifiedAt = null;
- 注册preUpdate事件监听,更新时自动写入带微秒的当前时间:
<?php namespace App\EventListener; use App\Entity\Thing; use Doctrine\ORM\Events; use Doctrine\Persistence\Event\LifecycleEventArgs; class ThingUpdateListener { public function preUpdate(LifecycleEventArgs $args): void { $entity = $args->getObject(); if (!$entity instanceof Thing) { return; } $entity->setModifiedAt(new \DateTimeImmutable('now')); } public static function getSubscribedEvents(): array { return [Events::preUpdate => 'preUpdate']; } }
最后把数据库中modified_at字段的类型修改为DATETIME(6),避免数据库层面截断微秒,该方案下Doctrine原生的乐观锁校验会自动生效,不会出现同秒并发漏判的问题。
方案2:自定义Persister完全替换更新逻辑
如果必须使用你写的原生SQL、完全替换默认persister->update()流程,按以下步骤实现:
- 编写自定义Persister类,继承Doctrine默认的
BasicEntityPersister,覆写update()方法,在方法内执行你的自定义更新SQL,自行处理参数绑定、影响行数校验、更新后实体字段同步逻辑——注意更新影响行数为0时必须抛出OptimisticLockException,否则会丢失并发保护能力。 - 在实体映射配置中直接指定自定义Persister类,Doctrine会自动替换默认的持久化实现:
#[ORM\Entity(repositoryClass: ThingRepository::class)] #[ORM\PersisterClass(CustomThingPersister::class)] class Thing { // 实体字段定义 }
注意:该方案需要自行处理所有字段更新、版本校验、实体状态同步逻辑,版本升级后需要跟进Doctrine内部接口变化,维护成本较高,非必要不选。
内容的提问来源于stack exchange,提问作者Joaquim d'Souza
相关产品推荐
相关产品推荐

