2016-04-25 12 views
2

特定の投稿をデータベースにインポートするには、次のコードがあります。投稿が既に存在するかどうかをチェックします。そうでない場合は、新しいものが作成されます。複数のDoctrineインスタンスを使用して重複する行

このスクリプトはcronジョブで実行されています。ただし、手動で実行する必要がある場合もあります。このスクリプトの2つのインスタンスが同時に実行されていることがあります。これが起こると、重複レコードが作成されます。なぜこれが可能かは分かりません。

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)最も簡単な解決策は、同じコマンドの実行を同時に防止することです。

$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)を使用すると、パフォーマンス上の利点を取得したい場合 あなたはあなただけのforeachで例外をキャッチすることができます)https://github.com/ffreitas-br/command-lock-bundle

2を使用することができます2つのコマンドを並列に実行すると、メッセージキューについて考える。 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

iは 'UniqueConstraintViolationException'は私が私のエンティティへの調整を行う必要があるでしょうか? – Peter

+0

おかげさまで、回答が更新され、detach()呼び出しが追加されました。 –

関連する問題