दिलचस्प पोस्ट
एक छवि सी # का आकार बदलें पहचान कॉलम मूल्य अचानक 1001 में एसक्यूएल सर्वर पर कूदता है JQuery के साथ एचटीएमएल टिप्पणी का चयन LINQ का सबसे कठिन या सबसे गलतफहमी वाला पहलू क्या है? उद्देश्य-सी में एक सदस्य चर के नाम पर एक अंडरस्कोर क्या दर्शाता है? Egg_info त्रुटि के कारण पीआईपी के माध्यम से स्थापित नहीं किया जा सकता डेटा के स्रोत के रूप में वैश्विक चर के साथ PHP सत्र साइड इफेक्ट चेतावनी लेन () फ़ंक्शन की लागत क्या सी # में कोई सीएसवी पाठक / लेखक पुस्तकालय हैं? colgroup में टेक्स्ट-संरेखण केंद्र का उपयोग करना क्या मैं मॉलोक का परिणाम निकालूं? file_get_contents () UTF-8 वर्ण टूटता है स्थिर सदस्यों को सी ++ में परिभाषित करना संग्रह संशोधित किया गया था; LISTBox से ListItem को निकालने पर गणन त्रुटि को निष्पादित नहीं कर सकता क्या है ((संरचना का नाम *) शून्य -> ​​ख) सी 11 में अपरिभाषित व्यवहार का कारण बनता है?

MySQLdb का उपयोग करते हुए कर्सर को बंद करने के लिए

मैं एक WSGI वेब ऐप का निर्माण कर रहा हूं और मेरे पास एक MySQL डाटाबेस है मैं MySQLdb का उपयोग कर रहा हूं, जो कर्सर को निष्पादित करने और परिणाम प्राप्त करने के लिए प्रदान करता है। कर्सर प्राप्त करने और बंद करने के लिए मानक अभ्यास क्या है? विशेष रूप से, मेरे कर्सर कितने समय चाहिए? क्या मुझे प्रत्येक लेनदेन के लिए एक नया कर्सर मिलना चाहिए?

मेरा मानना ​​है कि कनेक्शन को करने से पहले आपको कर्सर बंद करना होगा। लेन-देन के सेट को खोजने के लिए कोई महत्वपूर्ण लाभ है, जिसे इंटरमीडिएट कमिट की आवश्यकता नहीं है ताकि आपको प्रत्येक लेनदेन के लिए नए कर्सर नहीं मिलें? क्या नए कर्सर प्राप्त करने के लिए बहुत अधिक उपरि है, या क्या यह सिर्फ एक बड़ा सौदा नहीं है?

वेब के समाधान से एकत्रित समाधान "MySQLdb का उपयोग करते हुए कर्सर को बंद करने के लिए"

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

मॉड्यूल के 1.2.5 संस्करण के अनुसार, MySQLdb.Connection निम्नलिखित कोड ( जीथूब ) के साथ संदर्भ मैनेजर प्रोटोकॉल का कार्यान्वयन करता है :

 def __enter__(self): if self.get_autocommit(): self.query("BEGIN") return self.cursor() def __exit__(self, exc, value, tb): if exc: self.rollback() else: self.commit() 

पहले with ही कई मौजूदा क्यू एंड ए हैं, या आप __enter__ के "साथ" कथन को समझ सकते हैं, लेकिन अनिवार्य रूप से क्या होता है कि ब्लॉक के with शुरू होने पर __enter__ कार्यान्वित किया with है, और ब्लॉक के with छोड़ने पर __exit__ । यदि आप उस ऑब्जेक्ट को बाद में संदर्भित करने का इरादा रखते हैं, तो आप एक नाम पर __enter__ द्वारा __enter__ गए ऑब्जेक्ट को बाँध करने के लिए with EXPR as VAR वैकल्पिक सिंटैक्स का उपयोग कर सकते हैं। इसलिए, उपरोक्त क्रियान्वयन को देखते हुए, यहां आपके डेटाबेस की जांच करने का एक आसान तरीका है:

 connection = MySQLdb.connect(...) with connection as cursor: # connection.__enter__ executes at this line cursor.execute('select 1;') result = cursor.fetchall() # connection.__exit__ executes after this line print result # prints "((1L,),)" 

प्रश्न अब है, ब्लॉक के with निकलने के बाद कनेक्शन और कर्सर क्या हैं? उपरोक्त दिखाए गए __exit__ पद्धति को केवल self.rollback() या self.rollback() कहते हैं, और उन तरीकों में से न तो close() विधि कॉल करने जाते हैं। कर्सर में कोई __exit__ परिभाषित परिभाषित नहीं है – और यदि ऐसा होता है तो इससे कोई फर्क नहीं पड़ता, क्योंकि केवल कनेक्शन का प्रबंध करना है। इसलिए, ब्लॉक के with निकलने के बाद दोनों कनेक्शन और कर्सर खुले रहते हैं। उपरोक्त उदाहरण में निम्न कोड जोड़कर यह आसानी से पुष्टि की जाती है:

 try: cursor.execute('select 1;') print 'cursor is open;', except MySQLdb.ProgrammingError: print 'cursor is closed;', if connection.open: print 'connection is open' else: print 'connection is closed' 

आपको आउटपुट "कर्सर खुला है; कनेक्शन खुला है" देखना चाहिए stdout पर मुद्रित

मेरा मानना ​​है कि कनेक्शन को करने से पहले आपको कर्सर को बंद करना होगा।

क्यूं कर? MySQL सी एपीआई , जो कि MySQLdb का आधार है, किसी भी कर्सर ऑब्जेक्ट को लागू नहीं करता है, जैसा कि मॉड्यूल दस्तावेज में उल्लिखित है : "MySQL कर्सर का समर्थन नहीं करता है, हालांकि, कर्सर आसानी से अनुकरण कर रहे हैं।" दरअसल, MySQLdb.cursors.BaseCursor वर्ग सीधे object से प्राप्त करता object और प्रतिबद्ध / रोलबैक के संबंध में कर्सर पर कोई प्रतिबंध नहीं लगाता। एक ओरेकल डेवलपर ने यह कहा था :

cnx.commit () cur.close () से पहले मेरे लिए सबसे तार्किक लगता है शायद आप इस नियम से जा सकते हैं: "कर्सर को बंद करें यदि आपको इसकी ज़रूरत नहीं है।" इस प्रकार कर्सर को बंद करने से पहले () प्रतिबद्ध करें अंत में, कनेक्टर / पायथन के लिए, यह बहुत अंतर नहीं करता है, लेकिन या अन्य डेटाबेस शायद यह हो सकता है।

मुझे उम्मीद है कि इस विषय पर "मानक अभ्यास" करने के लिए जितनी करीब हो सकेगा

लेन-देन के सेट को खोजने के लिए कोई महत्वपूर्ण लाभ है, जिसे इंटरमीडिएट कमिट की आवश्यकता नहीं है ताकि आपको प्रत्येक लेनदेन के लिए नए कर्सर नहीं मिलें?

मुझे बहुत संदेह है, और ऐसा करने की कोशिश में, आप अतिरिक्त मानव त्रुटि का परिचय दे सकते हैं एक सम्मेलन पर निर्णय लेने और इसके साथ छड़ी करने के लिए बेहतर।

क्या नए कर्सर प्राप्त करने के लिए बहुत अधिक उपरि है, या क्या यह सिर्फ एक बड़ा सौदा नहीं है?

ओवरहेड नगण्य है, और डेटाबेस सर्वर को बिल्कुल भी स्पर्श नहीं करता है; यह पूरी तरह से MySQLdb के कार्यान्वयन के भीतर है आप BaseCursor.__init__ को github पर देख सकते हैं यदि आप जानना चाहते हैं कि क्या हो रहा है जब आप नया कर्सर बनाते हैं

पिछली बार जब हम with चर्चा कर रहे थे, शायद अब आप समझ सकते हैं कि MySQLdb.Connection वर्ग __enter__ और __exit__ विधियां आपको ब्लॉक के with प्रत्येक में एक नया कर्सर ऑब्जेक्ट देते हैं और इस पर नज़र रखने में परेशान न करें या इसे बंद करें ब्लॉक का अंत यह काफी हल्के है और अपनी सुविधा के लिए विशुद्ध रूप से मौजूद है।

यदि यह वास्तव में आप के लिए महत्वपूर्ण है कि कर्सर ऑब्जेक्ट को माइक्रोमैनेज करना है, तो आप संदर्भित कर सकते हैं कि कर्सर ऑब्जेक्ट की कोई परिभाषा नहीं है __exit__ विधि। उस मामले के लिए, आप ब्लॉक ऑब्जेक्ट को ब्लॉक से बाहर निकलने पर ही बंद करने के लिए मजबूर करने के लिए इसका इस्तेमाल भी कर सकते हैं। इसे आउटपुट "my_curs बंद कर दिया गया है; my_conn बंद है":

 from contextlib import closing import MySQLdb with closing(MySQLdb.connect(...)) as my_conn: with closing(my_conn.cursor()) as my_curs: my_curs.execute('select 1;') result = my_curs.fetchall() try: my_curs.execute('select 1;') print 'my_curs is open;', except MySQLdb.ProgrammingError: print 'my_curs is closed;', if my_conn.open: print 'my_conn is open' else: print 'my_conn is closed' 

ध्यान दें कि with closing(arg_obj) तर्क ऑब्जेक्ट के __enter__ और __exit__ विधियों को कॉल नहीं करेगा; यह ब्लॉक के with ही तर्क ऑब्जेक्ट की close विधि को कॉल करेगा। (इसे क्रियान्वयन में देखने के लिए, बस __enter__ , __exit__ साथ क्लास Foo को परिभाषित करें, और सरल print स्टेटमेंट वाले close विधियों की तुलना करें और with Foo(): pass करते समय क्या होता है इसकी तुलना करें with Foo(): pass जब आप with closing(Foo()): pass ।) इसके दो महत्वपूर्ण प्रभाव हैं:

सबसे पहले, यदि स्वतः हस्ताक्षरित मोड सक्षम होता है, तो MySQLdb सर्वर पर एक स्पष्ट लेनदेन BEGIN करेगा जब आप with connection प्रयोग with connection और ब्लॉक के अंत में लेन-देन को वापस ले लें या फिर रोलबैक करें। ये MySQLdb के डिफ़ॉल्ट व्यवहार हैं, जिसका उद्देश्य आपको किसी भी और सभी डीएमएल स्टेटमेंटों को तुरंत बनाए रखने के MySQL के डिफ़ॉल्ट व्यवहार से सुरक्षित करना है। MySQLdb मानता है कि जब आप किसी संदर्भ प्रबंधक का उपयोग करते हैं, तो आप एक लेनदेन चाहते हैं, और सर्वर पर ऑटोकॉमीट सेटिंग को बायपास करने के लिए स्पष्ट BEGIN का उपयोग करता है। यदि आप with connection उपयोग करने के लिए उपयोग किया जाता है, तो आप शायद सोचें कि ऑटोकोम्मिट अक्षम है जब वास्तव में यह केवल बाईपास किया जा रहा था। यदि आप अपने कोड को closing करते हैं और ट्रांसेक्शनल अखंडता खो देते हैं तो आपको अप्रिय आश्चर्य हो सकता है; आप परिवर्तनों को रोलबैक करने में सक्षम नहीं होंगे, आप संगतता की बग देख सकते हैं और यह तुरंत स्पष्ट नहीं हो सकता है क्यों

दूसरा, with closing(MySQLdb.connect(user, pass)) as VAR कनेक्शन के ऑब्जेक्ट को VAR से जोड़ता है, इसके विपरीत with MySQLdb.connect(user, pass) as VAR , जो with MySQLdb.connect(user, pass) as VAR को एक नया कर्सर ऑब्जेक्ट को बांधता है । उत्तरार्द्ध मामले में आपके पास कनेक्शन ऑब्जेक्ट पर सीधा पहुंच नहीं होगी! इसके बजाय, आपको कर्सर के connection विशेषता का उपयोग करना होगा, जो मूल कनेक्शन के लिए प्रॉक्सी पहुंच प्रदान करता है। कर्सर बंद होने पर, इसके connection विशेषता को None सेट किया जाता है यह एक अनजान कनेक्शन में परिणाम है जो निम्न में से एक होने तक चारों ओर रह जाएगा:

  • कर्सर के सभी संदर्भ निकाल दिए जाते हैं
  • कर्सर क्षेत्र से बाहर चला जाता है
  • कनेक्शन बार बाहर
  • कनेक्शन मैन्युअल रूप से सर्वर प्रशासन उपकरण के माध्यम से बंद कर दिया गया है

आप ओपन कनेक्शन (वर्कबेन्च में या SHOW PROCESSLIST का उपयोग करके ) की निगरानी करके इसका परीक्षण कर सकते हैं:

 with MySQLdb.connect(...) as my_curs: pass my_curs.close() my_curs.connection # None my_curs.connection.close() # throws AttributeError, but connection still open del my_curs # connection will close here 

कीवर्ड 'के साथ' का उपयोग करके इसे फिर से लिखना बेहतर है 'के साथ' कर्सर को बंद करने के बारे में ध्यान रखना होगा (यह महत्वपूर्ण है क्योंकि यह स्वचालित रूप से अप्रबंधित संसाधन है) लाभ यह अपवाद के मामले में भी कर्सर को बंद कर देगा।

 from contextlib import closing import MySQLdb ''' At the beginning you open a DB connection. Particular moment when you open connection depends from your approach: - it can be inside the same function where you work with cursors - in the class constructor - etc ''' db = MySQLdb.connect("host", "user", "pass", "database") with closing(db.cursor()) as cur: cur.execute("somestuff") results = cur.fetchall() # do stuff with results cur.execute("insert operation") # call commit if you do INSERT, UPDATE or DELETE operations db.commit() cur.execute("someotherstuff") results2 = cur.fetchone() # do stuff with results2 # at some point when you decided that you do not need # the open connection anymore you close it db.close() 

मुझे लगता है कि आप अपने सभी निष्पादनों के लिए एक कर्सर का इस्तेमाल करने की कोशिश कर रहे हैं, और अपने कोड के अंत में इसे बंद कर लेंगे। इसके साथ काम करना आसान है, और इसमें कुशलता के फायदे भी हो सकते हैं (उस पर मुझे उद्धरण न दें)।

 conn = MySQLdb.connect("host","user","pass","database") cursor = conn.cursor() cursor.execute("somestuff") results = cursor.fetchall() ..do stuff with results cursor.execute("someotherstuff") results2 = cursor.fetchall() ..do stuff with results2 cursor.close() 

मुद्दा यह है कि आप एक कर्सर के निष्पादन के परिणाम एक अन्य चर में संग्रहीत कर सकते हैं, जिससे आपके कर्सर को दूसरा निष्पादन करने के लिए मुक्त कर सकते हैं। यदि आप fetchone () का उपयोग कर रहे हैं, तो आपको इस तरह से समस्याएं आती हैं, और आपको पहली क्वेरी से सभी परिणामों के जरिए दोहराए जाने से पहले दूसरा कर्सर निष्पादन करना होगा।

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

नोट: यह उत्तर PyMySQL के लिए है , जो कि MySQLdb के लिए ड्रॉप-इन प्रतिस्थापन है और MySQLdb का नवीनतम संस्करण प्रभावी रूप से MySQLdb को बनाए रखा जा रहा है। मेरा मानना ​​है कि सब कुछ यहाँ विरासत MySQLdb के बारे में भी सच है, लेकिन जांच नहीं की है।

सबसे पहले, कुछ तथ्य:

  • सिंटैक्स के with पायथन __enter__ मैनेजर की __enter__ विधि को __enter__ के साथ __enter__ से पहले कहता है, और इसके बाद __exit__ विधि।
  • कनेक्शनों में एक __enter__ विधि होती है जो कर्सर को बनाने और वापस लाने के अलावा कुछ भी नहीं करती है, और एक __exit__ विधि है जो या तो वापस करती है या वापस रोल करती है (एक अपवाद फेंक दिया गया था या नहीं)। यह कनेक्शन बंद नहीं करता है
  • PyMySQL में कर्सर पूरी तरह से पायथन में लागू एक अमूर्त है; MySQL में ही कोई समकक्ष अवधारणा नहीं है 1
  • कर्सर के पास एक __enter__ विधि है जो कुछ भी नहीं करती है और एक __exit__ विधि जो कर्सर को "बंद करती है" (जिसका अर्थ है कर्सर के संदर्भ को उसके मूल कनेक्शन के __exit__ बंद करना और कर्सर पर संग्रहीत किसी भी डेटा को फेंकने का अर्थ है)।
  • कर्सर उन कनेक्शन के संदर्भ को पकड़ते हैं जो उन्हें उत्पन्न कर चुके हैं, लेकिन उनके द्वारा बनाए गए कर्सर के संबंध में कनेक्शन नहीं हैं।
  • कनेक्शन एक __del__ विधि है जो उन्हें बंद कर देता है
  • प्रति https://docs.python.org/3/reference/datamodel.html , CPython (डिफ़ॉल्ट पायथन कार्यान्वयन) संदर्भ गणना का उपयोग करता है और स्वचालित रूप से किसी ऑब्जेक्ट को हटा देता है, जब एक बार संदर्भों की संख्या शून्य हो जाती है।

इन चीजों को एक साथ रखकर, हम देखते हैं कि इस तरह के भोलेदार कोड सिद्धांत में समस्याग्रस्त हैं:

 # Problematic code, at least in theory! import pymysql with pymysql.connect() as cursor: cursor.execute('SELECT 1') # ... happily carry on and do something unrelated 

समस्या यह है कि कनेक्शन ने कुछ भी बंद नहीं किया है वास्तव में, यदि आप ऊपर दिए गए कोड को एक पायथन खोल में पेस्ट करते हैं और फिर एक MySQL खोल में SHOW FULL PROCESSLIST , तो आप उस निष्क्रिय कनेक्शन को देख सकेंगे जो आपने बनाया था। चूंकि MySQL की डिफ़ॉल्ट संख्या 151 कनेक्शन है, जो कि बहुत बड़ी नहीं है, आप सैद्धांतिक रूप से समस्याओं में चलना शुरू कर सकते हैं अगर आपके पास इन कनेक्शनों को खोलने के कई प्रक्रियाएं थीं।

हालांकि, CPython में, एक बचत अनुग्रह है जो यह सुनिश्चित करता है कि ऊपर की तरह मेरे कोड की तरह कोड आपको ओपन कनेक्शनों के भार के आसपास छोड़ने का कारण नहीं होगा। यह बचत अनुग्रह यह है कि जैसे ही cursor गुंजाइश से बाहर निकल जाते हैं (जैसे कि यह फ़ंक्शन जिसमें इसे खत्म किया गया था, या cursor को दूसरे को सौंपा जाता है), इसकी संदर्भ गणना शून्य मानती है, जिससे इसे हटाया जा सकता है, जिससे कनेक्शन का संदर्भ गिनती शून्य है, जिससे कनेक्शन __del__ विधि को कहा जाता है जिससे कनेक्शन को बल बंद हो जाता है। यदि आप पहले से ही अपने पायथन शेल में कोड चिपक चुके हैं, तो आप अब cursor = 'arbitrary value' चलकर इसे अनुकरण कर सकते हैं; जैसे ही आप ऐसा करते हैं, आपके द्वारा खोले गए कनेक्शन SHOW PROCESSLIST आउटपुट से गायब हो जाएंगे।

हालांकि, इस पर निर्भर असहनीय है, और सैद्धांतिक रूप से सीपीआईथॉन के अलावा अन्य पायथन कार्यान्वयन में विफल हो सकता है। क्लीनर, सिद्धांत रूप में, स्पष्ट रूप से होगा। बंद करें .close() कनेक्शन (डेटाबेस को कनेक्शन को मुक्त करने के लिए बिना ऑब्जेक्ट को नष्ट करने के लिए पायथन की प्रतीक्षा किए बिना) यह अधिक मजबूत कोड इस तरह दिखता है:

 import contextlib import pymysql with contextlib.closing(pymysql.connect()) as conn: with conn as cursor: cursor.execute('SELECT 1') 

यह बदसूरत है, लेकिन अजगर पर निर्भर नहीं है कि आप अपने ऑब्जेक्ट्स को नष्ट कर सकते हैं (सीमित उपलब्ध संख्या में) डेटाबेस कनेक्शन

ध्यान दें कि कर्सर को बंद करने पर, यदि आप कनेक्शन को पहले से ही इस तरह से बंद कर रहे हैं, तो पूरी तरह से व्यर्थ है।

अंत में, यहां माध्यमिक प्रश्नों का उत्तर देने के लिए:

क्या नए कर्सर प्राप्त करने के लिए बहुत अधिक उपरि है, या क्या यह सिर्फ एक बड़ा सौदा नहीं है?

नहीं, एक कर्सर का इन्स्तांत करने से माइस् SQL को बिल्कुल भी नहीं मारा जाता है और मूल रूप से कुछ भी नहीं है

लेन-देन के सेट को खोजने के लिए कोई महत्वपूर्ण लाभ है, जिसे इंटरमीडिएट कमिट की आवश्यकता नहीं है ताकि आपको प्रत्येक लेनदेन के लिए नए कर्सर नहीं मिलें?

यह स्थितिजन्य और कठिन है, जिसमें सामान्य उत्तर देना है। जैसा कि https://dev.mysql.com/doc/refman/en/optimizing-innodb-transaction-management.html कहते हैं, "एक एप्लिकेशन को प्रदर्शन समस्याएं मिल सकती हैं यदि यह प्रति सेकंड हजारों बार किए, और अलग-अलग प्रदर्शन समस्याएं यह केवल 2-3 घंटे ही करता है " । आप हर प्रतिबद्धता के लिए एक प्रदर्शन ओवरहेड देते हैं, लेकिन लेनदेन को अधिक समय तक छोड़कर, आप अन्य कनेक्शनों की संभावना को लॉक के लिए इंतजार करते समय बढ़ाते हैं, डेडलॉक के अपने जोखिम को बढ़ाते हैं, और अन्य कनेक्शनों द्वारा किए गए कुछ खोजों की लागत में संभावित रूप से वृद्धि करते हैं ।


1 MySQL का निर्माण होता है, यह कर्सर कहता है, लेकिन वे केवल संग्रहीत कार्यविधियों में मौजूद होते हैं; वे PyMySQL cursors से पूरी तरह से अलग हैं और यहां प्रासंगिक नहीं हैं।

मैं इसे php और mysql जैसी करने का सुझाव देता हूं पहले डेटा के मुद्रण से पहले अपने कोड की शुरुआत में शुरू करें इसलिए यदि आपको एक कनेक्ट त्रुटि मिलती है तो आप 50x प्रदर्शित कर सकते हैं (याद न करें कि आंतरिक त्रुटि क्या है) त्रुटि संदेश और इसे पूरे सत्र के लिए खोलें और इसे बंद कर दें जब आप जानते हैं कि आपको इसे अब और नहीं चाहिए