在Symfony2中的$ em-> clear()时出现未定义的索引错误 [英] Undefined index error upon $em->clear() in Symfony2

查看:90
本文介绍了在Symfony2中的$ em-> clear()时出现未定义的索引错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经编写了一个Symfony命令来从API导入一些数据.它可以工作,但是问题是当我在数据库中插入大JSON时,我的PHP内存使用量增加了.每次导入活动后,我的unitOfWork都会增加"2".

I have written a Symfony command to import some data from an API. It works but the problem is my PHP memory usage increases when I insert a big JSON in my database. And my unitOfWork increases by '2' to after each activty import.

我已经取消了所有用过的对象的设置,并且当您要进行大量批处理时,我已经阅读了Symfony2的文档:

I have already unset all my used objects, and I have read the documentation of Symfony2 when you want to do massive batch: http://www.doctrine-project.org/blog/doctrine2-batch-processing.html

但是当我使用$em->clear()时,我的实体管理器会出现此错误:

But when I use $em->clear() my entity manager gives this error:

通知:未定义的索引:到应用程序的路径\ vendor \ doctrine \ lib \ Doctrine \ ORM \ UnitOfWork.php第2228行中的000000007b56ea7100000000e366c259

Notice: Undefined index: 000000007b56ea7100000000e366c259 in path-to-application\vendor\doctrine\lib\Doctrine\ORM\UnitOfWork.php line 2228

这是我完整的代码:

 /**
 * @see Command
 */
protected function configure() {
  $this
    ->setName('ks:user:runkeepersync')
    ->setDescription('Synchroniser les activités d\'un utilisateur runkeeper')
    ->setDefinition(array(
      new InputArgument('access_token', InputArgument::REQUIRED, 'Access token'),
    ))
}

/**
 * @see Command
 */
protected function execute(InputInterface $input, OutputInterface $output) {
  $accessToken = $input->getArgument('access_token');
  $em = $this->getContainer()->get('doctrine')->getEntityManager();
  $UserHasServices = $em->getRepository('KsUserBundle:UserHasServices')->findOneByToken($accessToken);
  if (!is_object($UserHasServices) ) {
    echo "Impossible de trouver l'utilisateur qui possède le jeton ".$accessToken."";
  }
  $user    = $UserHasServices->getUser();
  $service = $UserHasServices->getService();
  echo "avant de requérir l'api : ".memory_get_usage()."\n";
  try {
    $rkApi = $this->getContainer()->get('ks_user.runkeeper');
    $rkApi->setAccessToken($accessToken);
    $activities  = $rkApi->getFitnessActivities(0,25);
    $nbParPages  = 25;
    $nomberActivitites = $activities->size;
    $aActivities = $activities->items;
    $nbPages =  floor ($nomberActivitites/$nbParPages);
    $aEndurance = array("Running", "Cycling", "Mountain Biking", "Walking", "Hiking", "Downhill Skiing", "Cross-Country Skiing", "Snowboarding", "Skating","Wheelchair", "Rowing", "Elliptical", "Other");
    $aEnduranceUnderWater = array("Swimming");
    $enduranceOnEarthType = $em->getRepository('KsActivityBundle:SportType')->findOneByLabel("endurance");
    if (!is_object($enduranceOnEarthType) ) {
      echo "Impossible de trouver le type de sport d'endurance";
    }
    $enduranceUnderWaterType = $em->getRepository('KsActivityBundle:SportType')->findOneByLabel("endurance_under_water");
    if (!is_object($enduranceUnderWaterType) ) {
      echo "Impossible de trouver le type de sport d'endurance sous l'eau ";
    }
    echo "Après avoir récupéré 25 activités : ".memory_get_usage()."\n";
    $a = 0;
    for($i=0;$i<=$nbPages;$i++){
      if($i!=0){
        $activities  = $rkApi->getFitnessActivities($i,25);
        $aActivities = $activities->items;
      }
      foreach ($aActivities as $activity) {
        $a = $a+1;
        $codeSport = $this->formatNameSport($activity->type);
        $sport = $em->getRepository('KsActivityBundle:Sport')->findOneByCodeSport($codeSport);
        if (!is_object($sport) ) {
          $sport = new \Ks\ActivityBundle\Entity\Sport();
          $sport->setLabel($codeSport);
          $sport->setCodeSport($codeSport);
          $sport->setSportType($enduranceOnEarthType);
          $em->persist($sport);
          $em->flush();
        }
        $activityDetail = json_decode($rkApi->requestJSONHealthGraph($activity->uri));
        if(in_array($activity->type, $aEndurance)){
          $urlActivitieDetail = $activityDetail->activity;
          $ActivitySessionEnduranceOnEarth = new \Ks\ActivityBundle\Entity\ActivitySessionEnduranceOnEarth($user);
          isset($activity->total_distance)? $ActivitySessionEnduranceOnEarth->setDistance($activity->total_distance) : "";
          isset($activity->duration)? $ActivitySessionEnduranceOnEarth->setDuration($this->secondesToTimeDuration($activity->duration)) : "";
          isset($activity->start_time)?  $ActivitySessionEnduranceOnEarth->setIssuedAt(new \DateTime($activity->start_time)) : "";
          $ActivitySessionEnduranceOnEarth->setModifiedAt(new \DateTime('Now'));
          $ActivitySessionEnduranceOnEarth->setSport($sport);
          isset($activityDetail->total_calories)?  $ActivitySessionEnduranceOnEarth->setCalories($activityDetail->total_calories) : "";
          isset($activityDetail->climb)?  $ActivitySessionEnduranceOnEarth->setElevationGain($activityDetail->climb) : "";
          $maxElevation = 0;
          $minElevation = 10000;
          if(isset($activityDetail->path)){
            foreach($activityDetail->path as $gpsPoint){
              if($gpsPoint->altitude > $maxElevation){
                $maxElevation = $gpsPoint->altitude;
              }
              if($gpsPoint->altitude < $minElevation){
                $minElevation = $gpsPoint->altitude;
              }
            }
            $ActivitySessionEnduranceOnEarth->setElevationMin($minElevation);
            $ActivitySessionEnduranceOnEarth->setElevationMax($maxElevation);
          }
          $em->persist($ActivitySessionEnduranceOnEarth);
          $em->flush();
          //Pour chaque activité on a un identifiant relatif au service qu'on synchronise
          $ActivityComeFromService = new \Ks\ActivityBundle\Entity\ActivityComeFromService();
          $ActivityComeFromService->setActivity($ActivitySessionEnduranceOnEarth);
          $ActivityComeFromService->setService($service);
          $ActivityComeFromService->setIdWebsiteActivityService($activity->uri);
          $ActivityComeFromService->setSourceDetailsActivity($rkApi->requestJSONHealthGraph($activity->uri));
          $ActivityComeFromService->setTypeSource("JSON");
          $em->persist($ActivityComeFromService);
          $em->flush();
          echo "Import de l'activite num ".$a." type :".$activity->type." effectue avec success \n";
          unset($ActivitySessionEnduranceOnEarth);
          unset($ActivityComeFromService);
          echo "UnitOFWOrk -> ".$em->getUnitOfWork()->size()."\n";
        }
        if(in_array($activity->type, $aEnduranceUnderWater)){
          $ActivitySessionEnduranceUnderWater = new \Ks\ActivityBundle\Entity\ActivitySessionEnduranceUnderWater($user);
          isset($activity->total_distance)? $ActivitySessionEnduranceUnderWater->setDistance($activity->total_distance) : "";
          isset($activity->duration)? $ActivitySessionEnduranceUnderWater->setDuration($this->secondesToTimeDuration($activity->duration)) : "";
          isset($activity->start_time) && !empty($activity->start_time)?  $ActivitySessionEnduranceUnderWater->setIssuedAt(new \DateTime($activity->start_time)) : "";
          $ActivitySessionEnduranceUnderWater->setModifiedAt(new \DateTime('Now'));
          $ActivitySessionEnduranceUnderWater->setSport($sport);
          isset($activityDetail->total_calories)?  $ActivitySessionEnduranceUnderWater->setCalories($activityDetail->total_calories) : "";
          isset($activityDetail->notes)?  $ActivitySessionEnduranceUnderWater->setDescription($activityDetail->notes) : "";
          $em->persist($ActivitySessionEnduranceUnderWater);
          $em->flush();
          $ActivityComeFromService = new \Ks\ActivityBundle\Entity\ActivityComeFromService();
          $ActivityComeFromService->setActivity($ActivitySessionEnduranceUnderWater);
          $ActivityComeFromService->setService($service);
          $ActivityComeFromService->setIdWebsiteActivityService($activity->uri);
          $ActivityComeFromService->setSourceDetailsActivity($rkApi->requestJSONHealthGraph($activity->uri));
          $ActivityComeFromService->setTypeSource("JSON");
          $em->persist($ActivityComeFromService);
          $em->flush();
          echo "Import de l'activité num ".$a." type :".$activity->type." effectué avec succès\n";
          unset($ActivitySessionEnduranceUnderWater);
          unset($ActivityComeFromService);
        }
        echo "Après chaque activité : ".memory_get_usage()."\n";
        unset($sport);
        unset($activityDetail);
        $em->clear();
      }
    }
  } catch (\Exception $e) {
    throw $e;
  }
}

谢谢,@ AdrienBrault.我已经使用--env=prod --no-debug进行了测试,确实它消耗的内存更少,但是内存仍会增加.我怎样才能真正清除实体经理?并稳定内存?

Thanks, @AdrienBrault. I have tested with --env=prod --no-debug, and it is true that it consumes less memory, but the memory still increase. How can I really clear the entity manager? and stabilize the memory?

推荐答案

Symfony在开发环境中记录所有SQL查询,因此首先需要禁用它

Symfony logs all SQL queries in dev environment, so first you need to disable it

// disable logger
$em->getConnection()->getConfiguration()->setSQLLogger(null);

您可以在实体上使用事件侦听器,也可能增加内存使用量.您可以像这样禁用它们

You may use event listeners on entities, it may also increase memory usage. You can disable them like so

// remove all listeners
foreach ($em->getEventManager()->getListeners() as $event => $listeners) {
    foreach ($listeners as $listener) {
        $em->getEventManager()->removeEventListener($event, $listener);
    }
}

从代码中删除unset,不需要它们,因为您在循环的每一步都清除了实体管理器.

Remove unset from your code, there is no need for them, as you clear entity manager every step of your loop.

// save and clear
$em->flush();
$em->getUnitOfWork()->clear();

请记住,如果将查询分组为一个flush,则该学说可以优化您的查询并提高性能.因此,最佳实践是对数据的某些部分执行一次flush.例如:

Remember that doctrine can optimize your queries, and improve perfomance if you group queries into one flush. So the best practice would be to execute flush once over some parts of your data. For example:

// collect 100 entities and then save them
if (($i % 100) == 0) {
    $em->flush();
    $em->getUnitOfWork()->clear();
}

这篇关于在Symfony2中的$ em-> clear()时出现未定义的索引错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆