2008-11-26 19 views
25

मैं लेनदेन के अंदर कुछ डेटा डालने के लिए Zend_Db का उपयोग कर रहा हूं। मेरा कार्य एक लेनदेन शुरू करता है और फिर एक और तरीका कहता है जो लेनदेन शुरू करने का प्रयास करता है और निश्चित रूप से विफल रहता है (मैं MySQL5 का उपयोग कर रहा हूं)। तो, सवाल यह है कि - मैं कैसे पता लगा सकता हूं कि लेनदेन शुरू हो चुका है? यहाँ कोड का एक नमूना सा है:यह पता लगाने के लिए कि लेनदेन पहले से ही शुरू हो चुका है?

 try { 
        Zend_Registry::get('database')->beginTransaction(); 

        $totals = self::calculateTotals($Cart); 
        $PaymentInstrument = new PaymentInstrument; 
        $PaymentInstrument->create(); 
        $PaymentInstrument->validate(); 
        $PaymentInstrument->save(); 

        Zend_Registry::get('database')->commit(); 
        return true; 

      } catch(Zend_Exception $e) { 
        Bootstrap::$Log->err($e->getMessage()); 
        Zend_Registry::get('database')->rollBack(); 
        return false; 
      } 

अंदर PaymentInstrument :: बनाने एक और beginTransaction बयान है कि अपवाद का कहना है कि है कि लेनदेन पहले से ही शुरू कर दिया गया है पैदा करता है।

उत्तर

2

Zend_Registry में startTransaction() के वापसी मूल्य को स्टोर करें, और बाद में जांचें।

2

Zend_Db के साथ-साथ एडेप्टर (दोनों mysqli और पीडीओ संस्करण) को देखते हुए मैं लेनदेन स्थिति की जांच करने के लिए वास्तव में कोई अच्छा तरीका नहीं देख रहा हूं। इसके बारे में ZF issue प्रतीत होता है - सौभाग्य से एक पैच जल्द ही बाहर आने के लिए।

समय के लिए, यदि आप अनौपचारिक जेडएफ कोड नहीं चलाएंगे, तो mysqli documentation कहता है कि आप वर्तमान में लेनदेन में हैं (त्रुटि ... ऑटोकॉमिट मोड में नहीं) के लिए SELECT @@autocommit कह सकते हैं।

+0

लगता है कि इस मुद्दे को उनके नजर में खो गया ... :( – xelurg

+0

सभी जेडएफ मुद्दों कहते हैं कि "अगले नाबालिग रिलीज में तय" जब तक वे वास्तव में तय कर रहे हैं। मुझे आशा है कि वे कहते हैं कि करने के लिए एक अच्छा कारण था, क्योंकि, यह बहुत भ्रामक है और बहुत से लोगों के लिए भ्रम पैदा करता है। –

+1

mysql क्लाइंट 'SELECT @@ autocommit के माध्यम से मेरे परीक्षण में; अभी भी लेनदेन के दौरान 1 लौटाता है। – ColinM

4

कोशिश करें/पकड़ें: अगर अपवाद यह है कि एक लेनदेन पहले ही शुरू हो चुका है (त्रुटि कोड या स्ट्रिंग का संदेश, जो भी हो), आगे बढ़ें। अन्यथा, अपवाद फिर से फेंक दें।

22

ढांचे के बारे में जानने का कोई तरीका नहीं है कि आपने लेनदेन शुरू किया है या नहीं। आप $db->query('START TRANSACTION') का भी उपयोग कर सकते हैं, जिसे ढांचे के बारे में पता नहीं चलेगा क्योंकि यह आपके द्वारा निष्पादित SQL कथन का विश्लेषण नहीं करता है।

बिंदु यह है कि यह ट्रैक करने के लिए एक आवेदन ज़िम्मेदारी है कि आपने लेनदेन शुरू किया है या नहीं। ऐसा कुछ नहीं है जो ढांचा कर सकता है।

मुझे पता है कि कुछ ढांचे इसे करने का प्रयास करते हैं, और कॉकैमामी चीजें करते हैं जैसे कि आप लेन-देन शुरू करने के कितनी बार गिनती करते हैं, केवल तभी हल करते हैं जब आप प्रतिबद्धता करते हैं या कई बार मेलबैक करते हैं। लेकिन यह पूरी तरह से फर्जी है क्योंकि आपके कार्यों में से कोई भी यह नहीं जान सकता कि प्रतिबद्ध या रोलबैक वास्तव में ऐसा करेगा, या यदि वे घोंसले की एक और परत में हैं।

(आप बता सकते हैं कि मैं इस चर्चा कई बार मिला है :-)

संपादित करें:Propel एक PHP डेटाबेस का उपयोग पुस्तकालय "आंतरिक लेन-देन" जो ऐसा नहीं करता अवधारणा का समर्थन करता है जब आप इसे बताते हैं तो प्रतिबद्ध करें। एक लेनदेन शुरू करने से केवल एक काउंटर बढ़ता है, और प्रतिबद्ध/रोलबैक काउंटर को कम करता है। नीचे एक मेलिंग सूची थ्रेड से एक अंश है जहां मैं कुछ परिदृश्यों का वर्णन करता हूं जहां यह विफल रहता है।


इसकी तरह या नहीं, लेनदेन "वैश्विक" हैं और वे ऑब्जेक्ट उन्मुख encapsulation का पालन नहीं करते हैं।

समस्या परिदृश्य # 1

मैं commit() फोन, मेरे परिवर्तन के लिए प्रतिबद्ध हैं? अगर मैं "आंतरिक लेनदेन" के अंदर दौड़ रहा हूं तो वे नहीं हैं। बाहरी लेनदेन का प्रबंधन करने वाला कोड वापस रोल करना चुन सकता है, और मेरे परिवर्तन या ज्ञान के बिना मेरे परिवर्तनों को त्याग दिया जाएगा।

उदाहरण के लिए:

  1. मॉडल ए: निष्पादित कुछ परिवर्तन
  2. मॉडल बी:: लेन-देन (मूक कोई को-अप)
  3. मॉडल बी शुरू: निष्पादित कुछ बदलाव लेन-देन
  4. मॉडल ए शुरू
  5. मॉडल बी: प्रतिबद्ध (मूक नो-ऑप)
  6. मॉडल ए: रोलबैक (मॉडल मॉडल परिवर्तन और मॉडल बी परिवर्तन दोनों को छोड़ देता है)
  7. मॉडल बी: डब्ल्यूटीएफ !? मेरे परिवर्तनों के साथ क्या हुआ?

समस्या परिदृश्य # 2

एक आंतरिक लेनदेन वापस रोल, यह वैध एक बाहरी लेनदेन द्वारा किए गए परिवर्तनों को निरस्त कर सकता है। जब बाहरी कोड पर नियंत्रण वापस कर दिया जाता है, तो इसका मानना ​​है कि इसका लेनदेन अभी भी सक्रिय है और प्रतिबद्ध होने के लिए उपलब्ध है। अपने पैच के साथ, वे commit() पर कॉल कर सकते हैं, और चूंकि ट्रांसडेप अब 0 है, तो यह चुपचाप $transDepth से -1 सेट करेगा और कुछ भी नहीं करने के बाद, सत्य लौटाएगा।

समस्या परिदृश्य # 3

अगर मैं commit() या rollback() फोन जब कोई लेन-देन सक्रिय है, यह $transDepth -1 सेट। अगले beginTransaction() स्तर को 0 तक बढ़ाता है, जिसका अर्थ है कि लेनदेन न तो वापस लुढ़काया जा सकता है और न ही प्रतिबद्ध किया जा सकता है। commit() पर बाद की कॉल लेन-देन को -1 या उससे आगे तक घटाएगी, और जब तक आप फिर से स्तर को बढ़ाने के लिए एक और अनावश्यक beginTransaction() नहीं करते हैं तब तक आप प्रतिबद्ध नहीं होंगे।

मूल रूप से, डेटाबेस लॉकिंग करने के लिए डेटाबेस को अनुमति दिए बिना एप्लिकेशन तर्क में लेनदेन प्रबंधित करने का प्रयास करना एक विनाशकारी विचार है। यदि आपके पास एक आवेदन अनुरोध में स्पष्ट लेनदेन नियंत्रण का उपयोग करने के लिए दो मॉडल की आवश्यकता है, तो आपको प्रत्येक मॉडल के लिए दो डीबी कनेक्शन खोलना होगा। फिर प्रत्येक मॉडल का अपना सक्रिय लेनदेन हो सकता है, जिसे एक दूसरे से स्वतंत्र रूप से प्रतिबद्ध या लुढ़काया जा सकता है।

(http://www.nabble.com/Zend-Framework-Db-Table-ORM-td19691776.html देखें)

+0

सच है, हालांकि यह निश्चित रूप से एक बेहद अच्छी सुविधा होगी। मुझे आश्चर्य है कि क्या ऐसा कुछ है जो हाइबरनेट या किसी भी परिपक्व दृढ़ता परतों में मौजूद है ... – xelurg

+1

प्रोपेल में यह है, लेकिन मुझे अभी भी विश्वास है कि यह एक फर्जी डिज़ाइन है। ऊपर मेरा संपादन देखें। –

+0

इस विषय पर वापस लौट रहा है ... उदाहरण के लिए जेपीए की अवधारणा है TransactionManager समान सी होगा जेडएफ के लिए तार्किक होना चाहिए? – xelurg

0

वेब का सामना करना पड़ पीएचपी में, स्क्रिप्ट लगभग हमेशा एक वेब अनुरोध के दौरान लागू किया जाता है। उस मामले में आप वास्तव में क्या करना चाहते हैं, एक लेनदेन शुरू करना है और स्क्रिप्ट समाप्त होने से ठीक पहले इसे प्रतिबद्ध करना है। अगर कुछ गलत हो जाता है, तो अपवाद फेंक दें और पूरी चीज वापस रोल करें। इस तरह:

wrapper.php: 

try { 
    // start transaction 
    include("your_script.php"); 
    // commit transaction 
} catch (RollbackException $e) { 
    // roll back transaction 
} 

स्थिति शेरिंग के साथ थोड़ा और जटिल हो जाती है, जहां आप कई कनेक्शन खोल सकते हैं। आपको उन कनेक्शनों की सूची में जोड़ना होगा जहां लेन-देन को स्क्रिप्ट के अंत में किया जाना चाहिए या वापस ले जाना चाहिए। हालांकि, यह समझें कि शेडिंग के मामले में, जब तक आपके पास लेन-देन पर वैश्विक म्यूटेक्स न हो, आप आसानी से समवर्ती लेन-देन की वास्तविक अलगाव या परमाणुता प्राप्त करने में सक्षम नहीं होंगे क्योंकि एक और स्क्रिप्ट आपके लेन-देन को शर्ड्स में कर रही है जबकि आप कर रहे हैं आपका अपना। हालांकि, आप MySQL के distributed transactions को देखना चाहेंगे।

0

क्वेरी टेक्स्ट के रूप में प्रारंभ करने के लिए ज़ेंड प्रोफाइलर का उपयोग करें और Zend_Db_Prfiler :: ट्रांज़ेक्शन क्वेरी प्रकार के रूप में क्वेरी टेक्स्ट के रूप में बाहर या पाठ के रूप में रोलबैक के साथ करें।(यह मानते हुए तक कोई -> क्वेरी() और Zend प्रोफाइलर अपने आवेदन में सक्षम "लेन-देन स्टार्ट")

1

आप भी अपने कोड लिख सकते हैं के अनुसार निम्नलिखित:

try { 
    Zend_Registry::get('database')->beginTransaction(); 
} 
catch (Exception $e) { } 

try { 
    $totals = self::calculateTotals($Cart); 

    $PaymentInstrument = new PaymentInstrument; 
    $PaymentInstrument->create(); 
    $PaymentInstrument->validate(); 
    $PaymentInstrument->save(); 

    Zend_Registry::get('database')->commit(); 
    return true; 
} 
catch (Zend_Exception $e) { 
    Bootstrap::$Log->err($e->getMessage()); 
    Zend_Registry::get('database')->rollBack(); 
    return false; 
} 
1

InnoDB के लिए आप में सक्षम होना चाहिए

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID(); 
0

मैं बिल Karwin के आकलन से असहमत उपयोग करने के लिए है कि लेन-देन का ट्रैक रखने के लिए शुरू कर दिया cockamamie है, हालांकि मुझे लगता है कि शब्द की तरह है।

मेरे पास ऐसी स्थिति है जहां मेरे पास ईवेंट हैंडलर फ़ंक्शन हैं जो मेरे द्वारा लिखे गए मॉड्यूल द्वारा बुलाए जा सकते हैं। मेरे कार्यक्रम हैंडलर डीबी में बहुत सारे रिकॉर्ड बनाते हैं। मुझे निश्चित रूप से वापस रोल करने की ज़रूरत है अगर कुछ सही ढंग से पारित नहीं किया गया हो या गायब हो या कुछ चला जाए, ठीक है, कॉकमामी। मैं नहीं जानता कि ईवेंट हैंडलर को ट्रिगर करने वाला बाहरी मॉड्यूल का कोड डीबी लेनदेन को संभालने वाला है, क्योंकि कोड अन्य लोगों द्वारा लिखा गया है। लेनदेन प्रगति पर है या नहीं, यह देखने के लिए मुझे डेटाबेस से पूछताछ करने का कोई तरीका नहीं मिला है।

तो मैं गिनती करता हूं। मैं CodeIgniter का उपयोग कर रहा हूं, जो अजीब चीजें करता है अगर मैं इसे नेस्टेड डीबी लेनदेन का उपयोग शुरू करने के लिए कहता हूं (उदा। इसे एक बार से अधिक trans_start() विधि को कॉल करना)। दूसरे शब्दों में, मैं केवल अपने ईवेंट हैंडलर में trans_start() को शामिल नहीं कर सकता, क्योंकि यदि कोई बाहरी फ़ंक्शन ट्रांस_स्टार्ट() का उपयोग कर रहा है, तो रोलबैक और काम सही तरीके से नहीं होते हैं। हमेशा संभावना है कि मैंने अभी तक उन कार्यों को सही तरीके से प्रबंधित करने के लिए नहीं पता लगाया है, लेकिन मैंने कई परीक्षण चलाए हैं।

मेरे सभी ईवेंट हैंडलर को यह जानने की ज़रूरत है कि क्या एक डीबी लेनदेन पहले से ही किसी अन्य मॉड्यूल द्वारा शुरू किया गया है? यदि ऐसा है, तो यह एक और नया लेनदेन शुरू नहीं करता है और किसी भी रोलबैक का सम्मान नहीं करता है या या तो करता है। यह भरोसा करता है कि अगर कुछ बाहरी कार्यों ने डीबी लेनदेन शुरू किया है तो यह रोलबैक/कामकाज भी संभालेगा।

मेरे पास कोडइग्निटर के लेनदेन विधियों के लिए रैपर फ़ंक्शन हैं और ये कार्य काउंटर में वृद्धि/कमी करते हैं।

function transBegin(){ 
    //increment our number of levels 
    $this->_transBegin += 1; 
    //if we are only one level deep, we can create transaction 
    if($this->_transBegin ==1) { 
     $this->db->trans_begin(); 
    } 
} 

function transCommit(){ 
    if($this->_transBegin == 1) { 
     //if we are only one level deep, we can commit transaction 
     $this->db->trans_commit(); 
    } 
    //decrement our number of levels 
    $this->_transBegin -= 1; 

} 

function transRollback(){ 
    if($this->_transBegin == 1) { 
     //if we are only one level deep, we can roll back transaction 
     $this->db->trans_rollback(); 
    } 
    //decrement our number of levels 
    $this->_transBegin -= 1; 
} 

मेरी स्थिति में, मौजूदा डीबी लेनदेन की जांच करने का यही एकमात्र तरीका है। और यह काम करता है। मैं यह नहीं कहूंगा कि "एप्लिकेशन डीबी लेनदेन का प्रबंधन कर रहा है"। यह वास्तव में इस स्थिति में असत्य है। यह बस यह जांच रहा है कि आवेदन के किसी अन्य भाग ने किसी भी डीबी लेनदेन शुरू कर दिए हैं, ताकि यह नेस्टेड डीबी लेनदेन बनाने से बच सके।

1

यह चर्चा काफी पुरानी है। जैसा कि कुछ ने बताया है, आप इसे अपने आवेदन में कर सकते हैं। पीएचपी के पास संस्करण 5> = 5.3.3 के बाद से एक तरीका है यह जानने के लिए कि क्या आप लेनदेन के बीच में हैं। पीडीपी :: inTransaction() सच या गलत देता है। लिंक http://php.net/manual/en/pdo.intransaction.php

+0

शायद ढांचे की डीबी परत लेनदेन की स्थिति की जांच के लिए इस पीडीओ विधि को समाहित नहीं करती है। मैं आपके जैसा ही उत्तर लेकर आया था, मैंने यहां आपके जवाब को देखने से पहले लगभग पोस्ट किया था। –

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