使用多个原则实例复制行


Duplicate rows using multiple Doctrine instances

我有以下一段代码将某些帖子导入我的数据库。它会检查帖子是否已存在。如果不是这种情况,它将创建一个新的。

此脚本在 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)最简单的解决方案是防止相同的命令同时运行。您可以使用 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();