यह पूछने के बजाय कि मानक अभ्यास क्या है, क्योंकि यह अक्सर अस्पष्ट और व्यक्तिपरक होता है, आप मार्गदर्शन के लिए मॉड्यूल की तलाश कर सकते हैं। सामान्य तौर पर, 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, और ब्लॉक __exit__छोड़ने पर निष्पादित होता है with। आप वैकल्पिक सिंटैक्स with EXPR as VARका उपयोग किसी ऑब्जेक्ट द्वारा लौटाए गए __enter__नाम से कर सकते हैं यदि आप उस ऑब्जेक्ट को बाद में संदर्भित करना चाहते हैं। इसलिए, ऊपर दिए गए कार्यान्वयन को देखते हुए, अपने डेटाबेस को क्वेरी करने का एक सरल तरीका है:
connection = MySQLdb.connect(...)
with connection as cursor:
cursor.execute('select 1;')
result = cursor.fetchall()
print result
अब सवाल यह है कि withब्लॉक से बाहर निकलने के बाद कनेक्शन और कर्सर की स्थिति क्या है ? __exit__ऊपर दिखाई गई विधि केवल self.rollback()या तो कॉल करती है self.commit(), और उन विधियों में से कोई भी close()विधि कॉल करने के लिए नहीं जाती है। कर्सर का कोई भी __exit__तरीका निर्धारित नहीं है - और अगर यह किया तो कोई फर्क नहीं पड़ेगा, क्योंकि withकेवल कनेक्शन का प्रबंधन कर रहा है। इसलिए, 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'
आपको आउटपुट "कर्सर खुला है; कनेक्शन खुला है" देखना चाहिए।
मेरा मानना है कि आपको कनेक्शन करने से पहले कर्सर को बंद करने की आवश्यकता है।
क्यों? MySQL सी एपीआई , जो आधार है MySQLdb, किसी भी कर्सर वस्तु को लागू नहीं करता है, मॉड्यूल दस्तावेज में निहित के रूप में: "MySQL कर्सर का समर्थन नहीं करता है, लेकिन, कर्सर को आसानी से नकल करते हैं।" दरअसल, MySQLdb.cursors.BaseCursorवर्ग सीधे विरासत में मिलता है objectऔर प्रतिबद्ध / रोलबैक के संबंध में अभिशापों पर इस तरह का कोई प्रतिबंध नहीं लगाता है। एक Oracle डेवलपर के पास यह कहने के लिए था :
cnx.commit () cur.close () से पहले मेरे लिए सबसे तार्किक लगता है। शायद आप नियम से जा सकते हैं: "यदि आपको इसकी आवश्यकता नहीं है तो कर्सर को बंद करें।" इस प्रकार कर्सर बंद करने से पहले प्रतिबद्ध ()। अंत में, कनेक्टर / पायथन के लिए, यह बहुत अंतर नहीं करता है, लेकिन या अन्य डेटाबेस यह हो सकता है।
मुझे उम्मीद है कि आप इस विषय पर "मानक अभ्यास" प्राप्त करने के करीब होंगे।
क्या लेन-देन के सेटों को खोजने के लिए कोई महत्वपूर्ण लाभ है जो मध्यवर्ती कमिट की आवश्यकता नहीं है ताकि आपको प्रत्येक लेनदेन के लिए नए कर्सर प्राप्त करने की आवश्यकता न हो?
मुझे इसमें बहुत संदेह है, और ऐसा करने की कोशिश में, आप अतिरिक्त मानवीय त्रुटि का परिचय दे सकते हैं। एक सम्मेलन पर निर्णय लेने और इसके साथ रहने के लिए बेहतर है।
क्या नए अभिशाप प्राप्त करने के लिए बहुत अधिक उपरि है, या यह सिर्फ एक बड़ी बात नहीं है?
ओवरहेड नगण्य है, और डेटाबेस सर्वर को बिल्कुल भी नहीं छूता है; यह पूरी तरह से MySQLdb के कार्यान्वयन के भीतर है। यदि आप एक नया कर्सर बनाते समय क्या हो रहा है, यह जानने के लिए वास्तव में उत्सुक हैं, तो आप गिटब पर देखBaseCursor.__init__ सकते हैं ।
पहले जब हम चर्चा कर रहे थे तब वापस जा रहे थे with, अब शायद आप समझ सकते हैं कि MySQLdb.Connectionकक्षा __enter__और __exit__विधियाँ आपको प्रत्येक में एक बिलकुल नया कर्सर ऑब्जेक्ट क्यों देती हैंwith ब्लॉक और इसे ट्रैक रखने या ब्लॉक के अंत में इसे बंद करने से परेशान नहीं करती हैं। यह काफी हल्का है और आपकी सुविधा के लिए पूरी तरह से मौजूद है।
यदि यह वास्तव में कर्सर ऑब्जेक्ट को micromanage करने के लिए आपके लिए महत्वपूर्ण है, तो आप इस तथ्य के लिए बनाने के लिए Referencelib.closing का उपयोग कर सकते हैं कि कर्सर ऑब्जेक्ट की कोई परिभाषित __exit__विधि नहीं है । उस मामले के लिए, आप इसका उपयोग कनेक्शन ऑब्जेक्ट को withब्लॉक से बाहर निकलने पर खुद को बंद करने के लिए मजबूर करने के लिए भी कर सकते हैं । यह आउटपुट "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__विधियों को कॉल नहीं करेगा ; इसे केवल तर्क वस्तु कहेंगेclosewith ब्लॉक के अंत में विधि को । (कार्रवाई में यह देखने के लिए, बस एक वर्ग को परिभाषित Fooके साथ __enter__, __exit__और closeतरीकों सरल युक्त printबयान, और तुलना क्या होता है जब आप करते हैं with Foo(): passक्या होता है जब आप क्या करनाwith closing(Foo()): pass है।) इस दो महत्वपूर्ण प्रभाव पड़ता है:
सबसे पहले, यदि ऑटोकॉमिट मोड सक्षम है, तो MySQLdb BEGINसर्वर पर एक स्पष्ट लेन-देन करेगा जब आप उपयोग करते हैं with connectionऔर ब्लॉक के अंत में लेनदेन को कमिट या रोलबैक करते हैं। ये MySQLdb के डिफ़ॉल्ट व्यवहार हैं, जिसका उद्देश्य आपको MySQL के डिफ़ॉल्ट व्यवहार से तत्काल किसी भी और सभी DML स्टेटमेंट को सुरक्षित रखना है। MySQLdb मानता है कि जब आप एक संदर्भ प्रबंधक का उपयोग करते हैं, तो आप एक लेनदेन चाहते हैं, और BEGINसर्वर पर ऑटोकॉमिट सेटिंग को बायपास करने के लिए स्पष्ट का उपयोग करता है। यदि आप उपयोग करने के लिए उपयोग किए जाते हैं with connection, तो आप सोच सकते हैं कि ऑटोकॉमिट अक्षम है जब वास्तव में यह केवल बायपास किया जा रहा था। यदि आप जोड़ते हैं तो आपको एक अप्रिय आश्चर्य हो सकता हैclosingअपने कोड के लिए और लेनदेन अखंडता खो; आप परिवर्तनों को रोलबैक करने में सक्षम नहीं होंगे, आप संक्षिप्तता बग देखना शुरू कर सकते हैं और यह तुरंत स्पष्ट नहीं हो सकता है कि क्यों।
दूसरा, with closing(MySQLdb.connect(user, pass)) as VARबांधता कनेक्शन वस्तु को VARकरने के लिए, इसके विपरीत में with MySQLdb.connect(user, pass) as VAR, जो बांधता है एक नया कर्सर वस्तु कोVAR । उत्तरार्द्ध मामले में आपके पास कनेक्शन ऑब्जेक्ट तक कोई सीधी पहुंच नहीं होगी! इसके बजाय, आपको कर्सर की connectionविशेषता का उपयोग करना होगा , जो मूल कनेक्शन तक प्रॉक्सी पहुंच प्रदान करता है। जब कर्सर बंद हो जाता है, तो इसकी connectionविशेषता सेट की जाती है None। यह एक परित्यक्त कनेक्शन का परिणाम है जो निम्नलिखित में से एक होने तक चारों ओर चिपक जाएगा:
- कर्सर के सभी संदर्भ हटा दिए जाते हैं
- कर्सर दायरे से बाहर चला जाता है
- कनेक्शन बार बाहर
- सर्वर प्रशासन उपकरण के माध्यम से कनेक्शन मैन्युअल रूप से बंद है
आप खुले कनेक्शनों की निगरानी के द्वारा (Workbench में या द्वारा इस परीक्षण कर सकते हैं का उपयोग करSHOW PROCESSLIST ) एक के बाद निम्नलिखित लाइनों एक निष्पादित करते समय:
with MySQLdb.connect(...) as my_curs:
pass
my_curs.close()
my_curs.connection
my_curs.connection.close()
del my_curs