个性化阅读
专注于IT技术分析

使用Symfony2和Doctrine增强数据库处理的5条简单技巧

本文概述

如今, Symfony开发人员中最普遍使用的是”对象对象关系映射”(ORM), 因为尽管有些人不同意这一点, 但它使开发人员与数据库之间的事情变得非常容易。

你应该已经知道, Doctrine 2在性能方面无法与旧版本的Doctrine 1进行比较, 例如:

  • Doctrine1实现ActiveRecord设计, 而D2实现DataMapper设计-这是最重要的区别。

  • D2需要PHP 5.3或更高版本, 并使用其好处, 例如名称空间。

  • D2分为一组较小的子项目:Doctrine Commons, Doctrine DBAL, Doctrine ORM(用于RDBMS)和Doctrine ODM(用于MongoDB)。

  • D2快得多。

  • D2支持注释。

教义无疑会使php程序员的生活更轻松。

在此处了解更多信息http://stackoverflow.com/questions/4400272/what-are-the-differences-between-doctrine1-and-doctrine2。

但是, 鼓励你(作为开发人员)提供高质量的结果, 应用程序的性能给开发人员和开发人员提供了很多话题, 并学习了一些在symfony2项目中使用学说来优化性能的技巧。

1.处理多个实体时避免对象水化

当你从数据库中检索许多寄存器以仅在视图中显示它们时(例如, 默认的CRUD生成的文件), 你应该考虑不要使用Doctrine的默认对象混合(返回Doctrine_collection对象, 该对象翻译为更多的内存和时间)。通过以下方法提高保湿性能。

而不是检索像Doctrine_collection的对象:

// In the controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$query = $repo >createQueryBuilder('a')
                ->where('a.role LIKE :role')
                ->setParameter('role', '%ADMIN%');
                
$results = $query->getQuery()->getResult();// Default hydration

改为申请:

// In the controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$query = $repo >createQueryBuilder('a')
                ->where('a.role LIKE :role')
                ->setParameter('role', '%ADMIN%');

$results = $query->getQuery()->getArrayResult();// Array hydration

$results = $query->getQuery()->getScalarResult();// Scalar hydration

2.如果你可以永久引用它, 请不要加载整个实体

让我们想象一个实体, 该实体具有从另一个数据库表引用的字段(一个User对象的字段Role具有Role表中的外键), 并且要持久化该用户对象, 你需要setRole($ roleObject)作为Role Entity 。

在那种情况下, 执行额外的find(例如, 用于请求参数的$ id)操作将强制执行不必要的附加数据库语句(这是我们所有人为解决此问题所要做的事情), 如下所示:

仅当你确定数据的来源时(当不经常清除环境缓存时), 才必须使用getReference。

但是有时候, getReference对于以前来说很方便。根据资源ID管理较大的集合(如操作)。这样, 你不必为每个资源都执行SELECT(find())语句。

// In the controller

$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$roleId = 2;
$role = $repo->find($roleId);

$user = new User();
$user->setName('Invisible man');
$user->setAge(27);
$user->setRole($role);
$em->persist($user);
$em->flush();

多亏了《教义》的参考代理, 你不必从数据库中检索整个实体, 而只需要将其与另一个实体相关联, 如下所示:

// In the controller

$em = $this->getDoctrine()->getManager(); 
$roleId = 2; 

$user = new User(); 
$user->setName('Invisible man');
$user->setAge(27); 
$user->setRole($em->getReference('ourcodeworldBundle:Users', $roleId)); 
$em->persist($user); 
$em->flush();

3.不要从循环中的实体获取引用的值

让我们想象一个实体, 该实体具有从另一个数据库表引用的字段(一个User对象的字段Role具有Role表中的外键), 并且要持久化该用户对象, 你需要setRole($ roleObject)作为Role Entity 。

我们返回显示给用户的视图, 然后使用如下所示的树枝循环渲染其名称, 角色名称和年龄:

{%for user in collectionUsers %}
<tr>
    <td>{{user.name}}</td>
    <td>{{user.role.name}}</td>{# Keep in mind that for every user , A QUERY will be executed asking for the name of its role !#}
    <td>{{user.age}}</td>
</tr>
{%endfor%}

因此, 当你渲染100个用户时, 你希望通过Join Query的结果和在Array Result中发送collectionUsers, 这将大大提高与以前的测试相比的性能, 因为最终将仅执行1个查询。

$qb = $this->createQueryBuilder('p');
      $qb->addSelect('a')
        ->innerJoin('p.role', 'a');

return $qb->getQuery()->getArrayResult(); 

4.使用’update’语句更新多行, 而不是对象持久化

当你必须更新多个实体时, 从数据库中检索它们并将其作为ORM实体进行迭代是一种非常糟糕的做法

$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Posts');

$newCreatedAt = new \DateTime();
$posts = $repo->findAll();
 
foreach ($posts as $post) {
    $post->setCreatedAt($newCreatedAt);
    $em->persist($post);
}

$em->flush();

建议改为申请:

$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Posts');
$newCreatedAt = new \DateTime();

$qb = $repo->createQueryBuilder('p');
    $qb->update()
        ->set('p.createdAt', ':newCreatedAt')
        ->setParameter('newCreatedAt', $newCreatedAt); 
$qb->getQuery()->execute();

5.如果没有必要, 不要只是为了获得一个简单的值而加载整个对象(带有关系)

除非你可以处理标量和数组值, 否则这是防止加载仅占用内存空间的不必要信息的好提示。

$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$age = $repo->createQuery(
    'SELECT z.age'.
    'FROM ourcodeworldBundle:Users z'.
    'WHERE z.id = :id'
)
->setParameter('id', 2)
->getSingleScalarResult();

return $age;//Just the number we need !

一些重要的建议:

  • 确保你正确创建查询。
  • 仅从数据库中加载你真正需要的内容, 然后返回需要水合或对象的对象。

在该学说的网站上, 有一个要点:

强烈建议使用APC之类的字节码缓存。字节码缓存消除了对每个请求解析PHP代码的需求, 并可以大大提高性能。

“如果你在乎性能, 而不使用字节码缓存, 那么你实际上就不在乎性能。请得到一个并开始使用它。” Stas Malyshev, PHP和Zend员工的核心贡献者

最后, 请谨慎将本文应用于你的项目。如果你的项目无法处理非常高的流量, 繁重的查询或具有低规格的项目, 则不必参加所有这些建议。

赞(0)
未经允许不得转载:srcmini » 使用Symfony2和Doctrine增强数据库处理的5条简单技巧

评论 抢沙发

评论前必须登录!