2009-09-29 25 views
40

एक MySQL डेटाबेस के साथ काम कर रहे एक PHP स्क्रिप्ट में, मुझे हाल ही में किसी अन्य लेनदेन के अंदर होने वाले बिंदु पर एक लेनदेन का उपयोग करने की आवश्यकता थी। मेरे सभी परीक्षण यह इंगित करते हैं कि यह ठीक काम कर रहा है, लेकिन मुझे इस उपयोग पर कोई दस्तावेज नहीं मिल रहा है।लेनदेन के भीतर MySQL लेनदेन

मैं सुनिश्चित करना चाहता हूं - लेन-देन के लेनदेन के भीतर लेनदेन क्या है? यदि हां, तो क्या यह पता लगाने का एक तरीका है कि आप नेस्टेड लेनदेन में कितने स्तर गहरे हैं? अग्रिम में, ब्रायन

उत्तर

46

मैनुअल की यह पृष्ठ आपको रुचि हो सकती (। यानी कितने पुनरावर्तन यह सामान्य करने के लिए वापस जाने के लिए ले जाएगा)

धन्यवाद: 12.3.3. Statements That Cause an Implicit Commit; कुछ वाक्यों के हवाले से: इस खंड (और उनके लिए कोई समानार्थी शब्द) में सूचीबद्ध

बयान परोक्ष , एक सौदे के अंत के रूप में यदि आप बयान निष्पादित करने से पहले एक COMMIT किया था।


और, पेज में आगे एक सा:

लेनदेन नियंत्रण और बयान ताला लगा। BEGIN, LOCK TABLES, SET autocommit = 1 (यदि मूल्य पहले से ही नहीं है 1), START TRANSACTION, UNLOCK TABLES

लेनदेन नेस्ट नहीं किया जा सकता:


भी इस paragrah देखें।
यह अंतर्निहित commit जब आप एक START TRANSACTION बयान या इसके समानार्थी शब्दों में से एक मुद्दा किसी भी वर्तमान लेनदेन के लिए प्रदर्शन का एक परिणाम है।


उम्मीद है कि इससे मदद मिलती है!

+0

'लेनदेन को उसी कनेक्शन में, या differents में भी घोंसला नहीं किया जा सकता है? –

+3

सामान्य तर्क कहता है कि अलग-अलग कनेक्शन एक-दूसरे के बारे में कुछ नहीं जानते हैं। इसलिए, एक कनेक्शन में लेनदेन को विभिन्न कनेक्शन में किसी अन्य लेनदेन के बारे में पता नहीं है। परीक्षण नहीं किया गया, लेकिन सच होना चाहिए। –

12

मैं यह सुनिश्चित करना चाहता हूं - लेनदेन mysql में मान्य लेनदेन के भीतर हैं?

सं

1

आप अपने परीक्षण methadology जांच करना चाह सकते। MaxDB के बाहर, MySQL नेस्टेड लेनदेन की तरह दूरस्थ रूप से कुछ भी समर्थन नहीं करता है।

+2

"MySQL नेस्टेड लेनदेन की तरह दूरस्थ रूप से कुछ भी समर्थन नहीं करता है।"क्या आप नहीं कहेंगे कि सेवपॉइंट्स नेस्टेड लेनदेन की तरह कुछ भी हैं? –

7

MySQL नेस्टेड लेनदेन का समर्थन नहीं करता है। हालांकि कुछ तरीके हैं जिन्हें आप अनुकरण कर सकते हैं। सबसे पहले, आप लेन-देन के रूप में सेवपॉइंट्स का उपयोग कर सकते हैं, जिससे आपको लेनदेन के दो स्तर मिलते हैं; मैंने परीक्षण के लिए इसका उपयोग किया है, लेकिन यदि आप इसे उत्पादन कोड में उपयोग करते हैं, तो मुझे सीमाओं के बारे में निश्चित नहीं है। एक आसान समाधान दूसरे begin transaction को अनदेखा करना और इसके बजाय काउंटर को बढ़ा देना है। प्रत्येक commit के लिए, आप इसे कम करते हैं। एक बार शून्य हो जाने पर, आप वास्तविक commit करते हैं। इसकी स्पष्ट सीमाएं हैं; उदाहरण के लिए।एक रोलबैक सभी लेनदेन वापस रोल करेगा, लेकिन ऐसे मामले के लिए जहां आप केवल त्रुटि-हैंडलिंग के लिए लेनदेन का उपयोग करते हैं, यह स्वीकार्य हो सकता है।

46

हर किसी की जवाब के विपरीत, आप प्रभावी रूप से लेन-देन के भीतर लेनदेन बना सकते हैं और यह वास्तव में आसान है। आप केवल SAVEPOINT स्थान बनाते हैं और लेन-देन के रोलबैक भाग में savepoint पर रोलबैक का उपयोग करते हैं, जहां savepoint वह भी नाम है जिसे आप savepoint देते हैं। MySQL दस्तावेज़ से लिंक: http://dev.mysql.com/doc/refman/5.0/en/savepoint.html और निश्चित रूप से, लेनदेन में कहीं भी कोई भी प्रश्न उस प्रकार का होना चाहिए जो पूर्ण रूप से प्रतिबद्ध है, या पूरा लेनदेन किया जाएगा।

उदाहरण:

START TRANSACTION; 

# queries that don't implicitly commit 

SAVEPOINT savepoint1; 

# queries that don't implicitly commit 

# now you can either ROLLBACK TO savepoint1, or just ROLLBACK to reverse the entire transaction. 

SAVEPOINT savepoint2; 

# queries that don't implicitly commit 

# now you can ROLLBACK TO savepoint1 OR savepoint2, or ROLLBACK all the way. 
# e.g. 

ROLLBACK TO savepoint1; 
COMMIT; # results in committing only the part of the transaction up to savepoint1 

PHP में मैं इस तरह कोड लिखा है, और यह पूरी तरह से काम करता है:

foreach($some_data as $key => $sub_array) { 
    $result = mysql_query('START TRANSACTION'); // note mysql_query is deprecated in favor of PDO 
    $rollback_all = false; // set to true to undo whole transaction 
    for($i=0;$i<sizeof($sub_array);$i++) { 
    if($sub_array['set_save'] === true) { 
     $savepoint = 'savepoint' . $i; 
     $result = mysql_query("SAVEPOINT $savepoint"); 
    } 
    $sql = 'UPDATE `my_table` SET `x` = `y` WHERE `z` < `n`'; // some query/queries 
    $result = mysql_query($sql); // run the update query/queries 

    $more_sql = 'SELECT `x` FROM `my_table`'; // get data for checking 
    $result = mysql_query($more_sql); 

    $rollback_to_save = false; // set to true to undo to last savepoint 
    while($row = mysql_fetch_array($result)) { 
     // run some checks on the data 
     // if some check says to go back to savepoint: 
     $rollback_to_save = true; // or just do the rollback here. 
     // if some check says to rollback entire transaction: 
     $rollback_all = true; 
    } 
    if($rollback_all === true) { 
     mysql_query('ROLLBACK'); // rollback entire transaction 
     break; // break out of for loop, into next foreach 
    } 
    if($rollback_to_save = true) { 
     mysql_query("ROLLBACK TO $savepoint"); // undo just this part of for loop 
    } 
    } // end of for loop 
    mysql_query('COMMIT'); // if you don't do this, the whole transaction will rollback 
} 
+4

इसका परीक्षण नहीं किया गया, लेकिन मुझे यह टिप्पणी करने की आवश्यकता महसूस हुई कि यह कितना सुंदर है। –

+2

@ मार्कोअरेलीओडेयू धन्यवाद ! मुझे नहीं लगता कि मुझे कभी भी मेरे किसी भी कोड के लिए ऐसी तारीफ मिली है। यह मेरे आवेदन में पूरी तरह से काम करता है, और ऐसा लगता है कि कुछ अन्य लोगों ने इसे काम करने के लिए भी प्राप्त किया है, अपवॉट्स द्वारा निर्णय लेना। –

+0

यह सही है, कोई भी एक लेन-देन के अंदर इस सेवपॉइंट पर सेवपॉइंट और रोलबैक सेट कर सकता है। लेकिन यहां बिंदु यह है कि लेनदेन का घोंसला संभव नहीं है क्योंकि आंतरिक लेनदेन शुरू करने से पहले बाहरी लेनदेन वक्तव्य पूरी तरह से प्रतिबद्ध होंगे और संभवतः ऐसा कुछ ऐसा है जिसे आप नहीं चाहते हैं। यह समस्याग्रस्त हो सकता है : उदाहरण के लिए यदि किसी के पास कक्षा हाउस और एक और कक्षा कक्ष है, तो प्रत्येक के पास डीबी बनाने के लिए अपना लेनदेन होता है; यहां आर बनाते हैं हाउस ऑब्जेक्ट के अंदर ओम ऑब्जेक्ट बाहरी घर के लेनदेन को तोड़ देगा !!! – sbrbot

5

इस सूत्र में कुछ महान जवाब,, कर रहे हैं लेकिन यदि आप के रूप में InnoDB का उपयोग आपका MySQL स्टोरेज इंजन और MySQL 5.0.3 या उच्चतर का उपयोग कर रहे हैं, आपको अपने हिस्से पर किसी भी अतिरिक्त काम की आवश्यकता के बिना बॉक्स के बाहर नेस्टेड लेनदेन मिलते हैं या इस धागे में दूसरों द्वारा वर्णित फैंसी तकनीकों में से कोई भी।

XA लेन-देन पर MySQL डॉक्स से:

MySQL 5.0.3 और ऊपर XA लेन-देन के लिए सर्वर-साइड समर्थन प्रदान करता है। वर्तमान में, यह समर्थन InnoDB स्टोरेज इंजन के लिए उपलब्ध है। MySQL XA कार्यान्वयन एक्स/ओपन सीएई दस्तावेज़ पर आधारित है वितरित लेनदेन प्रसंस्करण: एक्सए विशिष्टता। यह दस्तावेज़ द ओपन ग्रुप द्वारा प्रकाशित किया गया है और http://www.opengroup.org/public/pubs/catalog/c193.htm पर उपलब्ध है। वर्तमान एक्सए कार्यान्वयन की सीमाएं खंड ई 5, "एक्सए लेनदेन पर प्रतिबंध" में वर्णित हैं। बस आप के लिए

मेरे XA लेन-देन उदाहरण: XA लेन-देन के लिए

# Start a new XA transaction 
XA START; 

    # update my bank account balance, they will never know! 
    UPDATE `bank_accounts` SET `balance` = 100000 WHERE `id` = 'mine'; 

    # $100,000.00 is a bit low, I'm going to consider adding more, but I'm not sure so 
    # I will start a NESTED transaction and debate it... 
    XA START; 

     # max int money! woo hoo! 
     UPDATE `bank_accounts` SET `balance` = 2147483647 WHERE `id` = 'mine'; 

    # maybe thats too conspicuous, better roll back 
    XA ROLLBACK; 


# The $100,000 UPDATE still applies here, but the max int money does not, going for it! 
XA COMMIT; 

# Oh No! Sirens! It's the popo's!!! run!! 
# What the hell are they using ints for money columns anyway! Ahhhh! 

MySQL प्रलेखन:

मैं < 3 XA लेन-देन 4 ईवा!

+0

MySQL 5.6 पर कोशिश की। "एक्सए" कमांडों को स्ट्रिंग xid की आवश्यकता होती है, और नेस्टेड शुरू करने का प्रयास करने से यह पता चलता है: "त्रुटि 1399 (XAE07): XAER_RMFAIL: जब वैश्विक लेनदेन सक्रिय स्थिति में होता है तो कमांड निष्पादित नहीं किया जा सकता है" – HectorJ

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