2016-04-25 92 views
2

我有以下一段代码将某些帖子导入到我的数据库中。它检查一个帖子是否已经存在。如果不是这样,它会创建一个新的。使用多个Doctrine实例重复行

此脚本运行在cron作业中。但是,有时它也必须手动运行。可能发生这个脚本的两个实例同时运行。发生这种情况时,将创建重复记录。我看不出为什么会这样。

foreach ($posts as $post) { 
    $entity = new Post(); 
    $entity 
     ->setName($post->name) 
     ->setGender($post->gender()) 
     ->setDate(new \DateTime()) 
    ; 

    $em = $this->getContainer()->get('doctrine')->getManager(); 
    $checkEntity = $em->getRepository('SampleBundle:Post')->findOneBy(array(
     'name' => $post->name 
    )); 

    if (!$checkEntity) { 
     $em = $this->getContainer()->get('doctrine')->getManager(); 
     $em->persist($entity); 
     $em->flush(); 
    } 
} 

有人可以在这个问题上点点滴滴吗?

回答

1

1)最简单的解决方案是防止同时运行相同的命令。 你可以使用https://github.com/ffreitas-br/command-lock-bundle

2)可以正好赶上例外的foreach:

$em->persist($entity); 

try { 
    $em->flush(); 
} catch(UniqueConstraintViolationException $e) { 
    // Detach object to prevent exception with same entity on next flush() call. 
    $em->detach($entity); 
} 

如果需要保存只有一个实体实例:

$em->persist($entity); 

try { 
    $em->flush($entity); 
} catch(UniqueConstraintViolationException $e) { 
    // Nothing. 
} 

3)如果你想获得性能优势运行两条命令并行思考消息队列。 https://github.com/videlalvaro/RabbitMqBundle

监制:

foreach ($users as $user) { 
    $producer->produce(new Message($user['name'])); 
} 

消费者:

$name = $message->getName(); 

$entity = new Post(); 
$entity 
    ->setName($name) 
; 

$em = $this->getContainer()->get('doctrine')->getManager(); 
$em->persist($entity); 
$em->flush(); 
+0

如果我使用'UniqueConstraintViolationException'我应该让我的实体的任何调整? – Peter

+0

谢谢你好,答案已更新,添加detach()调用。 –