学说 2 和 ORM:如何缓存某个实体的每个查询?
Posted
技术标签:
【中文标题】学说 2 和 ORM:如何缓存某个实体的每个查询?【英文标题】:Doctrine 2 and ORM: how to cache every query for some entity? 【发布时间】:2013-03-27 14:23:56 【问题描述】:我花了很多时间来解决这个问题,并发现,正式地,我只能缓存一些自定义查询(查询对象上的 useResultCache(true))。但是我需要将应用程序中的每个查询缓存到某个表中。 EntityManager 上的 find* 方法呢?...
有人可以帮我找到一个优雅的解决方案吗?
【问题讨论】:
【参考方案1】:目前尚不支持,您最终应该在服务层或扩展存储库中处理它。
您正在寻找的是second level cache as in Hibernate,它基本上允许您插入键值存储,例如 redis、riak、mongodb 等,以便在操作是简单的 fetch 操作时使事情变得非常快。
https://github.com/doctrine/doctrine2/pull/580 有一个正在进行的拉取请求,它可能会出现在 Doctrine ORM 2.5 中,所以请查看那个。
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\ArrayCache;
class MyBaseRepo extends EntityRepository
public function __construct(EntityManager $entityManager)
parent::__construct($entityManager);
$cache = $em->getConfiguration()->getHydrationCache();
$this->cache = $cache ?: new ArrayCache();
public function find($id)
if (!$object = $this->tryFetchFromCache($id))
$object = parent::find($id);
$this->cache->save($this->generateKey($id), $object);
return $object;
protected function tryFetchFromCache($id)
if (!$object = $this->cache->fetch($this->generateCacheKey($id)))
return null;
return $this->getEntityManager()->merge($object);
public function generateCacheKey($id) /* ... */
您可以在引导应用程序时强制将其作为配置中 ORM 的基础存储库:
$configuration = new \Doctrine\ORM\Configuration();
$configuration->setDefaultRepositoryClassName('My\MyBaseRepo');
当您的任何实体发生更新/保存时,这也会强制您清除缓存条目:
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
class IssueUpdateSubscriber implements EventSubscriber
public function onFlush(OnFlushEventArgs $args)
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
if (!$cache = $em->getConfiguration()->getHydrationCache())
return;
$busted = array_merge(
$uow->getScheduledEntityUpdates(),
$uow->getScheduledEntityDeletions(),
);
foreach ($busted as $entityToClear)
$className = get_class($entityToClear);
$metadata = $em->getClassMetadata($className);
$repository = $em->getRepository($className);
$id = $metadata->getIdentifierValues($entityToClear);
$cache->delete($repository->generateCacheKey($id));
public function getSubscribedEvents()
return array(Events::onFlush);
请注意,此实现不会拦截给定实体对数据库的所有访问。它不会拦截代理引起的延迟加载初始化,并且非常脆弱,所以请设置一些适当的集成测试来支持它。
【讨论】:
感谢您的回答!能否请您向我展示缓存延迟加载实体的最佳方法?我将不胜感激:) @AndriiVasyliev 无法完成,这就是为什么我告诉你查看那个拉取请求。 好的,我明白了。感谢您的帮助!以上是关于学说 2 和 ORM:如何缓存某个实体的每个查询?的主要内容,如果未能解决你的问题,请参考以下文章