यह पूछने के बजाय कि मानक अभ्यास क्या है, क्योंकि यह अक्सर अस्पष्ट और व्यक्तिपरक होता है, आप मार्गदर्शन के लिए मॉड्यूल की तलाश कर सकते हैं। सामान्य तौर पर, 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__
विधियों को कॉल नहीं करेगा ; इसे केवल तर्क वस्तु कहेंगेclose
with
ब्लॉक के अंत में विधि को । (कार्रवाई में यह देखने के लिए, बस एक वर्ग को परिभाषित 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