我有以下一段代码将某些帖子导入我的数据库。它会检查帖子是否已存在。如果不是这种情况,它将创建一个新的。
此脚本在 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();