2012-10-25 18 views
6

मैं एक PHP फ़ंक्शन लिख रहा हूं जो किसी तालिका में डेटा के बड़े सेट को स्टोर/अपडेट करता है और इससे डेडलॉक हो सकता है। मैंने जांच की कोशिश की कि सिद्धांत के साथ एक असफल लेनदेन कैसे पुनः प्रयास करें लेकिन दुख की बात है कि ऑनलाइन कोई जानकारी नहीं मिल सका। इस बात की संभावना इस दृष्टिकोण डेटाबेस में डुप्लिकेट सम्मिलित जाएगा: मैं अंत में निम्न कोडसिद्धांत का उपयोग करके डेडलॉक के बाद लेनदेन का पुन: प्रयास कैसे करें?

$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" 
    ); 
} 

मेरा प्रश्न लिखा? यदि हां, तो मैं लेनदेन को वापस लाने के लिए सिद्धांत को कैसे मजबूर कर सकता हूं?

उत्तर

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

असल में, यह अब सत्य नहीं है, क्योंकि अपवाद 'EntityManager' बंद स्थिति में प्रवेश करता है और यह एक' ORMException 'फेंक देगा जिसमें कहा गया है कि इकाई प्रबंधक दूसरे प्रयास पर बंद है। सिद्धांत संस्करण 2.4। * – Mantas

+0

यह बंद होने पर इकाई प्रबंधक को रीसेट करने का तरीका है https://codedump.io/share/rjB45oiwtqwo/1/doctrine2-the-entitymanager-is-closed-how-to-reset-entity-manager-in- symfony2 –

-3

यदि आप ओआरएम का उपयोग नहीं कर रहे हैं तो इसका उपयोग करें कि यह स्वचालित रूप से डेडलॉक स्थिति प्रबंधित करेगा।

+0

मैं सम्मिलन के लिए ORM का उपयोग नहीं कर रहा हूँ। क्या आप समझा सकते हैं कि डेडलॉक स्वचालित रूप से कैसे संभाला जाता है? – Rorchackh

+1

रोर्चेक, यदि दोनों तालिकाओं में एक दूसरे के संदर्भ में विदेशी कुंजी हैं, उनमें से एक पूर्ण नहीं हो सकता है। यदि सबकुछ ठीक से मैप किया गया है, तो सिद्धांत हमेशा तालिका को निरंतर बाधा के साथ बनाए रखेगा, अनिवार्य बाधा के साथ एक को बनाए रखेगा * और * सही एफके मान सेट करने के लिए पहले संपादित करें। –

+3

सिद्धांत * एक ओआरएम है, और यह * डेडलॉक स्थिति स्वचालित रूप से * संभाल नहीं करता है। यह पहली डेटाबेस त्रुटि के साथ दुर्घटनाग्रस्त हो जाता है और जलता है और आसानी से पुनर्प्राप्त नहीं होता है। ओआरएम का उपयोग करने में समस्या यह है कि आप कहीं और समस्या को आउटसोर्सिंग प्रभावी ढंग से आउटसोर्स कर रहे हैं, और जब कहीं और गलत हो जाता है, तो गर्दन में इसे ठीक करने में भारी दर्द हो सकता है। ऑफ-द-शेल्फ ओआरएम का उपयोग करने के लिए आप जिस कीमत का भुगतान करते हैं। – 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; 
    } 
} 
संबंधित मुद्दे