Symfony2和Doctrine2:查询对象时的高内存使用率

时间:2013-10-21 15:46:52

标签: php symfony doctrine-orm

我有两个(对于这个问题相关)实体,它们是多个(证书)到一个(政策)关系:

  • 证书
  • 政策

......基本上看起来像这样:

class Policy {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Akm\CertificateBundle\Entity\Certificate", mappedBy="policies")
     */
    private $certificates;

    /**
     * Get template (assuming there is only one
     * per policy (which should be the case) and return the Certificate
     * object. If (for some reason) there is more than only one template,
     * then only the first one will be returned.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getTemplate() {
        $certificates = $this->getCertificates();
        foreach($certificates as $cert) {
           if ($cert->getIsTemplate()) {
              return $cert;
           }
        }
        return false;
    }
}

class Certificate {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="boolean", nullable=false)
     */
    private $isTemplate;

    /**
     * @ORM\ManyToOne(targetEntity="Akm\CertificateBundle\Entity\Policy", inversedBy="certificates")
     * @ORM\JoinColumn(name="policy_id", referencedColumnName="id", nullable=true)
     */
    private $policies;
}

(当然还有相应的getter和setter,由doctrine自动生成)这种方法的问题是,如果我调用一个控制器,它本身调用removeTemplate() - 函数,我得到一个{{ 1}};我认为,问题是foreach-loop,它获取证书对象并测试其属性Allowed memory size of 134217728 bytes exhausted (tried to allocate [...] bytes) in [...]。由于证书对象非常大,如果大约有80个或更多证书,则会导致内存使用率过高(导致出现错误消息)。

现在我想知道,我怎么能解决这个问题。我有两个想法/方法,但没有按预期工作。

第一个是isTemplate unset() - 变量,我知道,我不再需要它了:

$cert

然而,这并没有改变任何东西,控制器仍然使用相同数量的内存。

所以我想到用控制器替换控制器内部public function getTemplate() { $certificates = $this->getCertificates(); foreach($certificates as $cert) { if ($cert->getIsTemplate()) { return $cert; } else { unset($cert); } } return false; } - 函数的所有调用(其中getTemplate() - 变量是Policy-entity的对象):

$pol

(我使用了$template = $cert_repository->findBy( array('isTemplate' => true), array('policies' => $pol->getId()); 而不仅仅是Policy-object,因为StackOverflow-answer}

这种方法的问题是,我总是得到$pol->getId() - 错误,我不知道为什么。

我希望有人可以帮助我让其中一种方法起作用(我更喜欢第一种方法,因为我不需要在控制器中更改任何内容)。

提前致谢, katze_sonne

1 个答案:

答案 0 :(得分:1)

两种解决方案:

  • 您可以对结果进行分页
  • 您可以将结果水合成数组

你可以做这样的事情

$query = $this->cert_repository
              ->createQueryBuilder('p')
              ->select(array('p'))
              ->where('p.isTemplate = :isTemplate')->setParameter('isTemplate', true)
              ->andWhere('p.policies = :policies')->setParameter('policies', $pol->getId())
              ->getQuery()
              ->setFirstResult($offset)
              ->setMaxResults($limit);
return $query->getArrayResult();

基本上,当Doctrine水合对象时,它会将对象的数据引用到内存中,并且使用函数unset不会释放内存,但是将对象保存到数组中可以使用函数unset