2012-10-25 102 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的插入