Does Doctrine's second-level cache return stale results after entity updates without manual invalidation?
0 reputation · 06 Apr 2022, 06:41 UTC
0 reputation · 06 Apr 2022, 06:41 UTC
Doctrine's second-level cache stores entity data in a provider-specific backend, but it does not automatically invalidate entries when an entity is updated. Developers must manually clear or expire the cache, which can lead to stale reads if the invalidation strategy is not explicitly configured.
In Doctrine 2.x, the default ArrayCache provider has no time-to-live expiration, so cached entities persist indefinitely until explicitly cleared. Doctrine 3.x introduced default TTL-enabled providers like Redis that can expire entries automatically, though the ORM still requires explicit invalidation for updated entities.
The ORM offers multiple cache invalidation strategies—clearing the entire cache, invalidating single entities, or using annotations—but the documentation does not prescribe a single recommended approach. This leaves new projects without clear guidance on which strategy to adopt for optimal consistency versus performance.
Which cache invalidation approach provides the best balance between avoiding stale reads and maintaining performance in typical Doctrine applications, and does this vary significantly between Doctrine 2.x and 3.x?
35775 reputation · 06 Apr 2022, 16:54 UTC
Doctrine ORM's second-level cache does not automatically evict an entity region when that entity is updated, inserted, or deleted through the EntityManager. A later load by identifier in a new request can return the cached representation until the entry expires by TTL or is manually evicted. This concerns Doctrine ORM (PHP); its invalidation semantics are not the same as Hibernate ORM.
Confirmed: second-level cache entries are region-based and provider-specific. The ORM does not track database changes made outside the current EntityManager, by concurrent transactions, or through direct SQL, so cross-request staleness is expected without a TTL or invalidation strategy. Clearing the EntityManager does not clear the second-level cache.
Unconfirmed: claims that Doctrine 3.x ships default TTL-enabled providers or changes automatic invalidation behavior. Treat your installed version as the authoritative source until verified.
What is your installed Doctrine ORM version? Run composer show doctrine/orm. The version determines which documentation branch and cache API apply, and it changes whether version-specific guidance is relevant.
Enable second-level caching on an entity, update it through a separate EntityManager or direct SQL, then reload by ID in a new request and compare the returned data to the current database row. Inspect the provider backend before and after the update to confirm whether entries are evicted automatically.
Assumptions: you are using Doctrine ORM, not Doctrine DBAL alone, and the second-level cache is actually enabled. TTL reduces the stale window but does not eliminate it.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.