मानक अभ्यास क्या है, यह पूछने के बजाय, क्योंकि यह अक्सर अस्पष्ट और व्यक्तिपरक होता है, आप मार्गदर्शन के लिए स्वयं मॉड्यूल को देखने का प्रयास कर सकते हैं। सामान्य तौर पर, with
. का उपयोग करना किसी अन्य उपयोगकर्ता के रूप में सुझाए गए कीवर्ड एक अच्छा विचार है, लेकिन इस विशिष्ट परिस्थिति में यह आपको वह कार्यक्षमता नहीं दे सकता जिसकी आप अपेक्षा करते हैं।
मॉड्यूल के संस्करण 1.2.5 के अनुसार, MySQLdb.Connection
संदर्भ प्रबंधक प्रोटोकॉल
लागू करता है निम्नलिखित कोड के साथ (github
):
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
. के बारे में कई मौजूदा प्रश्नोत्तर हैं पहले से ही, या आप पायथन के "with" स्टेटमेंट को समझना
पढ़ सकते हैं। , लेकिन अनिवार्य रूप से क्या होता है कि __enter__
with
. की शुरुआत में निष्पादित होता है ब्लॉक करें, और __exit__
with
. छोड़ने पर निष्पादित होता है खंड मैथा। आप वैकल्पिक सिंटैक्स का उपयोग कर सकते हैं with EXPR as VAR
__enter__
. द्वारा लौटाई गई वस्तु को बाइंड करने के लिए एक नाम के लिए यदि आप उस वस्तु को बाद में संदर्भित करना चाहते हैं। तो, उपरोक्त कार्यान्वयन को देखते हुए, आपके डेटाबेस को क्वेरी करने का एक आसान तरीका यहां दिया गया है:
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.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 C API
, जो MySQLdb
. का आधार है , किसी भी कर्सर ऑब्जेक्ट को लागू नहीं करता है, जैसा कि मॉड्यूल दस्तावेज़ीकरण में निहित है:"MySQL कर्सर का समर्थन नहीं करता, हालांकि, कर्सर आसानी से अनुकरणीय होते हैं।"
दरअसल, MySQLdb.cursors.BaseCursor
क्लास सीधे object
. से इनहेरिट करता है और कमिट/रोलबैक के संबंध में कर्सर पर ऐसा कोई प्रतिबंध नहीं लगाता है। एक Oracle डेवलपर यह कहना था
:
cnx.commit() cur.close() से पहले मेरे लिए सबसे तार्किक लगता है। हो सकता है कि आप नियम से जा सकते हैं:"यदि आपको अब इसकी आवश्यकता नहीं है तो कर्सर को बंद कर दें।" इस प्रकार कर्सर को बंद करने से पहले () करें। अंत में, कनेक्टर/पायथन के लिए, इससे बहुत फर्क नहीं पड़ता, लेकिन या अन्य डेटाबेस इससे हो सकते हैं।
मुझे उम्मीद है कि यह उतना ही करीब होगा जितना आप इस विषय पर "मानक अभ्यास" करने जा रहे हैं।
<ब्लॉकक्वॉट>क्या ऐसे लेन-देन के सेट खोजने का कोई महत्वपूर्ण लाभ है, जिन्हें मध्यवर्ती प्रतिबद्धताओं की आवश्यकता नहीं है ताकि आपको प्रत्येक लेनदेन के लिए नए कर्सर न मिलें?
मुझे इसमें बहुत संदेह है, और ऐसा करने की कोशिश में, आप अतिरिक्त मानवीय त्रुटि का परिचय दे सकते हैं। एक सम्मेलन के बारे में फैसला करना और उस पर टिके रहना बेहतर है।
<ब्लॉकक्वॉट>क्या नए कर्सर प्राप्त करने के लिए बहुत अधिक खर्च होता है, या यह कोई बड़ी बात नहीं है?
ओवरहेड नगण्य है, और डेटाबेस सर्वर को बिल्कुल भी स्पर्श नहीं करता है; यह पूरी तरह से MySQLdb के कार्यान्वयन के भीतर है। आप BaseCursor.__init__
देख सकते हैं। जीथब पर
यदि आप वास्तव में यह जानने के लिए उत्सुक हैं कि नया कर्सर बनाते समय क्या हो रहा है।
पहले की बात करें जब हम with
. पर चर्चा कर रहे थे , शायद अब आप समझ सकते हैं कि क्यों MySQLdb.Connection
क्लास __enter__
और __exit__
विधियाँ आपको प्रत्येक with
. में एक बिलकुल नया कर्सर ऑब्जेक्ट देती हैं ब्लॉक करें और इसका ट्रैक रखने या ब्लॉक के अंत में इसे बंद करने की जहमत न उठाएं। यह काफी हल्का है और पूरी तरह से आपकी सुविधा के लिए मौजूद है।
यदि कर्सर ऑब्जेक्ट को माइक्रोमैनेज करना आपके लिए वास्तव में इतना महत्वपूर्ण है, तो आप contextlib.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 के डिफ़ॉल्ट व्यवहार हैं, जिसका उद्देश्य आपको किसी भी और सभी DML कथनों को तुरंत करने के MySQL के डिफ़ॉल्ट व्यवहार से बचाना है। 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
. पर सेट है . इसका परिणाम एक परित्यक्त कनेक्शन में होता है जो निम्न में से एक होने तक आसपास रहेगा:
- कर्सर के सभी संदर्भ हटा दिए गए हैं
- कर्सर दायरे से बाहर हो गया है
- कनेक्शन का समय समाप्त
- कनेक्शन मैन्युअल रूप से सर्वर व्यवस्थापन टूल के माध्यम से बंद किया जाता है
आप खुले कनेक्शन की निगरानी करके (कार्यक्षेत्र में या द्वारा इसका परीक्षण कर सकते हैं। 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