You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony中Doctrine二级缓存无法显示新增实体条目问题咨询

Doctrine二级缓存新增条目后findBy()返回旧列表问题

我在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并加载对应实体,完全不会去数据库查询新插入的条目。

正确处理方式

  1. 针对追加场景调整缓存策略
    即使现有实体不修改,READ_ONLY也不适合需要频繁新增条目的场景。建议改用NONSTRICT_READ_WRITE策略,同时确保实体的ID是自增主键(Doctrine能通过主键判断新实体):

    #[ORM\Cache(usage: "NONSTRICT_READ_WRITE", region: "append_only")]
    

    该策略下,新增实体后Doctrine会自动将新实体加入缓存,且不会影响原有缓存的实体数据。

  2. 避免缓存查询结果集
    如果你坚持使用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();
    

    这样每次查询都会去数据库获取最新的实体列表,同时单个实体依然会从二级缓存加载,兼顾性能和实时性。

  3. 精准更新缓存而非清空整个区域
    如果必须保留READ_ONLY且需要缓存查询结果,那在新增实体后不要清空整个区域,而是将新实体手动加入缓存:

    $newLog = new Log();
    // ... 填充实体数据
    $entityManager->persist($newLog);
    $entityManager->flush();
    
    // 将新实体加入二级缓存
    $cache = $entityManager->getCache();
    $cache->putEntity($newLog);
    

    但这种方式无法解决查询结果集的缓存问题,你仍需要处理查询结果的缓存失效,所以并不推荐。


内容的提问来源于stack exchange,提问作者chris_cm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:07:48