2012-10-25 36 views
6

我正在写一个PHP函数,它将大量数据存储到/更新到表中,并可能导致死锁。我试图调查如何重试失败的交易与教条,但可惜在网上找不到任何信息。我终于写了下面的代码如何使用Doctrine在死锁后重试事务?

$retry = 0; 
$done = false; 
while (!$done and $retry < 3) { 
    try { 

     $this->entityManager->flush(); 
     $done = true; 

    } catch (\Exception $e) { 
     sleep(1); 

     $retry++; 
    } 
} 

if ($retry == 3) { 
    throw new Exception(
     "[Exception: MySQL Deadlock] Too many people accessing the server at the same time. Try again in few minutes" 
    ); 
} 

我的问题:是有机会这一做法将在数据库中插入重复?如果是这样,我该如何强制Doctrine回滚交易?

回答

11

死锁返回错误1213,你应该在客户端处理

注意死锁和锁等待是不同的东西。在僵局中,没有“失败”的交易:他们都有罪。无法保证哪一个会回滚。

您必须使用rollback,您的样式代码将插入重复。例如,您应该:

$retry = 0; 

$done = false; 


$this->entityManager->getConnection()->beginTransaction(); // suspend auto-commit 

while (!$done and $retry < 3) { 

    try { 

     $this->entityManager->flush(); 

     $this->entityManager->getConnection()->commit(); // commit if succesfull 

     $done = true; 

    } catch (\Exception $e) { 

     $this->entityManager->getConnection()->rollback(); // transaction marked for rollback only 

     $retry++; 

    } 

} 

希望得到这个帮助。

+0

谢谢:)这至少给了我一个如何进行的想法。 – Rorchackh

+18

事实上,这不再是事实,因为在Exception'EntityManager'进入关闭状态的情况下,它会抛出一个'ORMException',表示实体管理器在第二次尝试时关闭。 Doctrine 2.4版本。* – Mantas

+0

这是关闭时如何重置entitymanager https://codedump.io/share/rjB45oiwtqwo/1/doctrine2-the-entitymanager-is-closed-how-to-reset-entity-manager-in- Symfony2的 –

-3

如果您不使用ORM,那么使用它会自动管理死锁情况。

+0

。你能解释如何自动处理死锁吗? – Rorchackh

+1

Rorchackh,如果两个表都有外键互相引用,其中一个不能为NOT NULL。如果一切正确映射,教义将始终坚持与可空约束的表,坚持强制性约束的*和*编辑第一个设置正确的FK值。 –

+3

Doctrine *是*一个ORM,它不*自动处理死锁情况。它会因第一个数据库错误而崩溃并且不易恢复。使用ORM的问题在于,您在其他地方将问题有效地外包,而当其他地方出现问题时,可能会在解决问题时产生巨大的痛苦。这是您使用现成的ORM支付的价格。 – StampyCode

1

这是我如何处理与Sf2.7重试失败的交易和学说2.4.7:

use Doctrine\Bundle\DoctrineBundle\Registry; 
use Doctrine\ORM\EntityManager; 

class Foo 
{ 
    /** 
    * @var Registry 
    */ 
    protected $doctrine; 

    public function __construct(Registry $registry) 
    { 
     $this->doctrine = $registry; 
    } 

    protected function doSomething($entity, $attempt) 
    { 
     $em = $this->getEntityManager(); 
     $conn = $em->getConnection(); 
     try{ 
      $conn->beginTransaction(); 
      $entity->setBar("baz"); 
      $em->flush(); 
      $conn->commit(); 
     } catch(\PDOException $e){ 
      $conn->rollBack(); 
      $attempt++; 
      if($attempt <= 3){ 
       $this->doSomething($repayment, $attempt); 
      } 
     } 
    } 

    /** 
    * @return EntityManager 
    */ 
    protected function getEntityManager() 
    { 
     /** @var EntityManager $em */ 
     $em = $this->doctrine->getManager(); 
     if(!$em->isOpen()){ 
      $this->doctrine->resetManager(); 
      $em = $this->doctrine->getManager(); 
     } 

     return $em; 
    } 
} 
我不使用ORM的插入