Symfony中Doctrine二级缓存无法显示新增实体条目问题咨询
我在Symfony 6.2.12 + Doctrine 2.15.3环境下启用了二级缓存,调试工具栏显示缓存命中正常,但通过EntityManager新增实体条目后,调用findBy()方法始终返回新增前的旧列表(仅新增条目,未修改现有实体)。移除ORM\Cache注解后新条目能正常显示,确认是缓存导致的问题。
doctrine.yaml配置
doctrine: dbal: url: '%env(resolve:DATABASE_URL)%' orm: auto_generate_proxy_classes: true naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: true mappings: App: is_bundle: false dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App second_level_cache: enabled: true regions: append_only: lifetime: 8640000 cache_driver: type: service id: cache.app
实体注解配置
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: LogRepository::class)] #[ORM\Cache(usage: "READ_ONLY", region: "append_only")] class Log { // ... 实体其他代码 }
控制器获取数据代码
$logs = $logRepository->findBy( $criteria, ['id' => 'DESC'], $limit, $offset );
目前我能通过清除整个实体缓存区域来让列表更新,但这种方式不符合预期:
/** @var \Doctrine\ORM\Cache $cache */ $cache = $this->entityManager->getCache(); $cache->evictEntityRegion(Log::class);
我原本以为READ_ONLY策略支持追加新条目,请问这是配置问题吗?
问题原因与解决方案
核心原因
Doctrine二级缓存的READ_ONLY策略仅缓存已存在的实体数据,并不会自动感知新插入的实体。更关键的是:findBy()这类查询的结果集(即实体列表)本身也会被缓存,而不仅仅是单个实体。当你第一次调用findBy()时,Doctrine会把查询结果的实体ID列表缓存起来,后续调用会直接从缓存中读取这些ID并加载对应实体,完全不会去数据库查询新插入的条目。
正确处理方式
针对追加场景调整缓存策略
即使现有实体不修改,READ_ONLY也不适合需要频繁新增条目的场景。建议改用NONSTRICT_READ_WRITE策略,同时确保实体的ID是自增主键(Doctrine能通过主键判断新实体):#[ORM\Cache(usage: "NONSTRICT_READ_WRITE", region: "append_only")]该策略下,新增实体后Doctrine会自动将新实体加入缓存,且不会影响原有缓存的实体数据。
避免缓存查询结果集
如果你坚持使用READ_ONLY,可以通过在查询时显式禁用查询缓存来绕过结果集缓存:$logs = $logRepository->createQueryBuilder('l') ->where(...) // 对应原$criteria条件 ->orderBy('l.id', 'DESC') ->setMaxResults($limit) ->setFirstResult($offset) ->getQuery() ->setCacheMode(\Doctrine\ORM\Query::CACHE_MODE_OFF) // 禁用查询缓存 ->getResult();这样每次查询都会去数据库获取最新的实体列表,同时单个实体依然会从二级缓存加载,兼顾性能和实时性。
精准更新缓存而非清空整个区域
如果必须保留READ_ONLY且需要缓存查询结果,那在新增实体后不要清空整个区域,而是将新实体手动加入缓存:$newLog = new Log(); // ... 填充实体数据 $entityManager->persist($newLog); $entityManager->flush(); // 将新实体加入二级缓存 $cache = $entityManager->getCache(); $cache->putEntity($newLog);但这种方式无法解决查询结果集的缓存问题,你仍需要处理查询结果的缓存失效,所以并不推荐。
内容的提问来源于stack exchange,提问作者chris_cm

