2010-04-28 14 views
5

मेरे पास दो अलग-अलग मॉड्यूल हैं जिनका स्वतंत्र रूप से उपयोग किया जा सकता है, लेकिन मॉड्यूल 2 मॉड्यूल 1 पर निर्भर है।पीडीओ लेनदेन से जुड़े नेस्टेड परमाणु संचालन में मदद की ज़रूरत है

मॉड्यूल 2 में एक ऑपरेशन है जिसे परमाणु होने की आवश्यकता है, और यह मॉड्यूल 1 में एक ऑपरेशन को कॉल करता है जिसे परमाणु भी होना चाहिए।

मान लिया जाये कि मैं पीडीओ को पीडीओ :: ATTR_ERRMODE निर्धारित किया है: पीएचपी गंभीर त्रुटि:: न आया हुआ अपवाद 'PDOException' संदेश के साथ

'वहां पहले से ही एक सक्रिय लेन-देन है' ERRMODE_EXCEPTION, भारी genericised निम्न और कोड कतरना इस पैदावार

Module1:

<?php 
class Module1 
{ 
    ... 
    public function atomicOperation($stuff) 
    { 
     $this->pdo->beginTransaction(); 
     try { 
      $stmt = $this->pdo->prepare(...); 
      ... 
      $this->pdo->commit(); 
     } 
     catch (Exception $ex) { 
      $this->pdo->rollBack(); 
      throw $ex; 
     } 
    } 
} 

Module2:

<?php 
class Module2 
{ 
    public $module1; 
    ... 
    public function atomicOperation($stuff) 
    { 
     $this->pdo->beginTransaction(); 
     try { 
      $stmt = $this->pdo->prepare(...); 
      ... 
      $this->module1->atomicOperation($stuff); 
      ... 
      $this->pdo->commit(); 
     } 
     catch (Exception $ex) { 
      $this->pdo->rollBack(); 
      throw $ex; 
     } 
    } 
} 

मुझे यकीन है कि इस बारे में जाने के लिए सबसे अच्छा तरीका है नहीं कर रहा हूँ - नेस्टेड ऑपरेशन को निश्चित रूप से स्वतंत्र रूप से बुलाया जाएगा और बिल्कुल परमाणु होना चाहिए जब इसे अपने अधिकार में बुलाया जाए। लेनदेन का प्रबंधन करने और परमाणु संरक्षण को संरक्षित करने के लिए कक्षा 'उपयोगकर्ता पर ऑनस रखना वांछनीय नहीं है क्योंकि मुझे यकीन है कि कक्षा के उपयोगकर्ता इसे कभी लागू नहीं करेंगे।

उत्तर

4

आपको अपनी खुद की कक्षा बनाने की आवश्यकता है जो पीडीओ बढ़ाता है और लेनदेन का प्रबंधन करता है। कुछ की तरह:

<?php 
class Db extends PDO{ 
    private $_inTrans = false; 

    public function beginTransaction(){ 
    if(!$this->_inTrans){ 
     $this->_inTrans = parent::beginTransaction(); 
    } 
    return $this->_inTrans; 
    } 

    public function commit(){ 
    if($this->_inTrans){ 
     $this->_inTrans = false; 
     return parent::commit(); 
    } 
    return true; 
    } 

    public function rollBack(){ 
    if($this->_inTrans){ 
     $this->_inTrans = false; 
     return parent::rollBack(); 
    } 
    return true; 
    } 

    public function transactionStarted(){ 
    return $this->_inTrans; 
    } 

} 

तुम अब भी सभी प्रश्नों मामले कुछ लेन-देन वहाँ शुरू कर दिया है में पारित की जाँच करने की जरूरत है।

मॉड्यूल 1:

<?php 
class Module1 
{ 
    ... 
    public function atomicOperation($stuff) 
    { 
     $transactionAlreadyStarted = $this->pdo->transactionStarted(); 
     if(!$transactionAlreadyStarted){ 
      $this->pdo->beginTransaction(); 
     } 
     try { 
      $stmt = $this->pdo->prepare(...); 
      ... 

      if(!$transactionAlreadyStarted && $this->pdo->transactionStarted()){ 
       $this->pdo->commit(); 
      } 
     } 
     catch (Exception $ex) { 
      if($this->pdo->transactionStarted()){ 
       $this->pdo->rollBack(); 
      } 
      throw $ex; 
     } 
    } 
} 

मॉड्यूल 2:

<?php 
class Module2 
{ 
    public $module1; 
    ... 
    public function atomicOperation($stuff) 
    { 
     $transactionAlreadyStarted = $this->pdo->transactionStarted(); 
     if(!$transactionAlreadyStarted){ 
      $this->pdo->beginTransaction(); 
     } 
     try { 
      $stmt = $this->pdo->prepare(...); 
      ... 
      $this->module1->atomicOperation($stuff); 
      ... 
      if(!$transactionAlreadyStarted && $this->pdo->transactionStarted()){ 
       $this->pdo->commit(); 
      } 
     } 
     catch (Exception $ex) { 
      if($this->pdo->transactionStarted()){ 
       $this->pdo->rollBack(); 
      } 
      throw $ex; 
     } 
    } 
} 
+0

कुछ fluff जोड़ा गया। आपके परमाणु संचालन अकेले लेनदेन या उनके आसपास के दोस्तों के साथ उपयोग करने में सक्षम होंगे। – Arkh

1

Arkh के समाधान है, हालांकि करीब है, गलत क्योंकि प्रतिबद्ध() और रोलबैक() कर रहे हैं मूल रूप से झूठ बोल रही है। रोलबैक() या प्रतिबद्ध() को कॉल करना सच हो सकता है जब कुछ भी वास्तव में नहीं हो रहा है।

इसके बजाय, आपको SAVEPOINTs का उपयोग करना चाहिए।

Savepoints are supported in some form or other in database systems like PostgreSQL, Oracle, Microsoft SQL Server, MySQL, DB2, SQLite (since 3.6.8), Firebird and Informix (since version 11.50xC3). Savepoints are also defined in the SQL standard.

अपने कस्टम डीबी वर्ग में, आप के लिए प्रतिबद्ध ओवरराइड, रोलबैक और beginTransaction() और SAVEPOINTs का उपयोग जहां उपयुक्त हो। आप ट्रांज़ेक्शन() में भी लागू करने का प्रयास कर सकते हैं, हालांकि सावधान रहें कि MySQL में अंतर्निहित काम करता है (तालिका बनाएं, इत्यादि) इस की विश्वसनीयता को गड़बड़ कर देगा।

यह blog post from 2008 वास्तव में मेरे द्वारा किए गए कार्यों का कार्यान्वयन है।

This code will only attempt to use the SAVEPOINT code if you’re using a database driver that supports it

संबंधित मुद्दे