Au lieu de se demander quelle est la norme de la pratique, car c'est souvent floue et subjective, vous pouvez essayer la recherche pour le module lui-même pour obtenir des conseils. En général, l'utilisation de l' with
mot-clé comme un autre utilisateur proposé est une excellente idée, mais dans ce cas précis, il ne peut pas vous donner tout les fonctionnalités que vous attendez.
À partir de la version 1.2.5 du module, MySQLdb.Connection
implémente le gestionnaire de contexte de protocole avec le code suivant (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()
Il existe plusieurs Q&A sur with
déjà, ou vous pouvez lire la Compréhension Python "avec la" déclaration, mais essentiellement ce qui se passe c'est qu' __enter__
s'exécute au démarrage de l' with
bloc, et __exit__
s'exécute à la sortie de l' with
bloc. Vous pouvez utiliser la syntaxe facultative with EXPR as VAR
de lier l'objet renvoyé par __enter__
d'un nom, si vous avez l'intention de la référence de l'objet plus tard. Donc, étant donné ce qui précède la mise en œuvre, voici une façon simple pour interroger votre base de données:
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,),)"
La question est maintenant de savoir, quels sont les états de la connexion et le curseur après la sortie de l' with
bloc? L' __exit__
méthode indiquée ci-dessus uniquement les appels self.rollback()
ou self.commit()
, et aucune de ces méthodes vont à l'appel de l' close()
méthode. Le curseur lui-même n'a pas d' __exit__
méthode définie. Par conséquent, la connexion et le curseur reste ouvert après la sortie de l' with
bloc. Ceci est facilement confirmé en ajoutant le code suivant à l'exemple ci-dessus:
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'
Vous devriez voir la sortie de "curseur est ouvert; connexion est ouverte" imprimé sur la sortie standard stdout.
Je crois que vous devez fermer le curseur avant de valider la connexion.
Pourquoi? L' API C MySQL, qui est la base pour MySQLdb
, ne pas mettre en œuvre tout objet curseur, implicite dans la documentation du module: "MySQL ne prend pas en charge les curseurs; toutefois, les curseurs sont facilement émulé." En effet, l' MySQLdb.cursors.BaseCursor
classe hérite directement de object
et n'impose aucune restriction sur les curseurs à l'égard de commit/rollback. Un Oracle developer avait ceci à dire:
cnx.commit() avant de cur.close() semble le plus logique pour moi. Peut-être que vous
qui peut passer par la règle: "Fermer le curseur si vous n'avez pas besoin de plus."
Donc commit() avant de fermer le curseur. En fin de compte, pour
Connecteur/Python, il n'a pas beaucoup de différence, mais ou d'autres
bases de données qu'il peut.
Je m'attends c'est aussi proche que vous allez obtenir à la "norme" sur ce sujet.
Est-il un avantage significatif à trouver des ensembles d'opérations qui ne nécessitent pas d'intermédiaire s'engage, de sorte que vous n'avez pas à obtenir de nouveaux curseurs pour chaque transaction?
J'en doute fort, et en essayant de le faire, vous pouvez introduire une erreur humaine. Mieux décider sur un projet de convention et le bâton avec elle.
Il y a beaucoup de frais généraux pour l'obtention de nouveaux curseurs, ou est-il tout simplement pas une grosse affaire?
La surcharge est négligeable, et ne touchez pas au serveur de base de données; c'est entièrement à l'intérieur de la mise en œuvre de MySQLdb. Vous pouvez regarder BaseCursor.__init__
sur github si vous êtes vraiment curieux de savoir ce qui se passe lorsque vous créez un nouveau curseur.
Remontant à plus tôt, quand nous discutions with
, peut-être que maintenant vous pouvez comprendre pourquoi l' MySQLdb.Connection
classe __enter__
et __exit__
méthodes vous donner un tout nouveau curseur de l'objet dans chaque with
bloc et ne pas la peine de garder trace de celui-ci ou de sa fermeture à la fin du bloc. Il est assez léger et il existe purement pour votre commodité.
Si c'est vraiment important pour vous de s'immiscer dans l'objet curseur, vous pouvez utiliser contextlib.fermeture pour compenser le fait que le curseur de l'objet n'a pas défini __exit__
méthode. Pour cette question, vous pouvez également l'utiliser pour forcer la connexion de l'objet à fermer lui-même à la sortie d'un with
bloc. Cela devrait sortie "curs est fermé; conn est fermé":
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'
Notez que with closing(arg_obj)
n'ira pas en appel de l'argument de l'objet __enter__
et __exit__
méthodes; il sera seulement appel à l'argument de l'objet close
méthode à la fin de l' with
bloc. (Pour le voir en action, il suffit de définir une classe à l' Foo
avec __enter__
, __exit__
, et close
méthodes contenant simple print
des déclarations, et de comparer ce qui se passe quand vous n' with Foo(): pass
de ce qui se passe quand vous n' with closing(Foo()): pass
.) Cela a deux conséquences importantes:
Tout d'abord, si le mode de validation automatique est activée, MySQLdb sera BEGIN
une transaction explicite sur le serveur lorsque vous utilisez with connection
et commit ou rollback de la transaction à la fin du bloc. Ce sont des comportements par défaut. Si vous avez l'habitude d'utiliser with connection
vous pourriez penser de validation automatique est désactivé alors qu'en réalité, c'est l'objet de connexion c'est la gestion de vos transactions "derrière les coulisses" grâce à l' with
de la syntaxe. Vous pourriez avoir une mauvaise surprise si vous ajoutez closing
de votre code et soudain, vos déclarations sont autocommitting!
Deuxièmement, with closing(MySQLdb.connect(user, pass)) as VAR
lie l' objet de connexion à VAR
, contrairement à with MySQLdb.connect(user, pass) as VAR
, qui se lie à un nouveau curseur objet d' VAR
. Dans ce dernier cas, vous n'avez pas un accès direct à l'objet de connexion! Au lieu de cela, vous devez utiliser le curseur de l' connection
d'attribut, qui fournit l'accès proxy à l'origine de la correction. Lorsque le curseur est fermé, son connection
de définir l'attribut None
. Il en résulte un abandon de la connexion qui va rester jusqu'à ce que l'un des cas suivants:
- Toutes les références à l'curseur sont supprimés
- Le curseur est hors de portée
- Le temps de connexion à
- La connexion est fermée manuellement via les outils d'administration de serveur
Vous pouvez le tester par la surveillance des connexions ouvertes dans Workbench tout en exécutant les lignes suivantes une par une:
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