Mysql
 sql >> Base de données >  >> RDS >> Mysql

Pourquoi le gestionnaire de contexte MySQLdb Connection ne ferme-t-il pas le curseur ?

Pour répondre directement à votre question :je ne vois aucun mal à conclure à la fin d'un with bloquer. Je ne peux pas dire pourquoi ce n'est pas fait dans ce cas. Mais, comme il y a peu d'activité sur cette question, j'ai effectué une recherche dans l'historique du code et j'y ajouterai quelques réflexions (suppositions ) pourquoi le close() peut ne pas être appelé :

  1. Il y a une petite chance que les appels à nextset() tournent peut lancer une exception - cela a peut-être été observé et considéré comme indésirable. C'est peut-être pourquoi la nouvelle version de cursors.py contient cette structure dans close() :

    def close(self):
        """Close the cursor. No further queries will be possible."""
        if not self.connection:
            return
    
        self._flush()
        try:
            while self.nextset():
                pass
        except:
            pass
        self.connection = None
    
  2. Il y a le potentiel (quelque peu éloigné) que cela puisse prendre un certain temps pour parcourir tous les résultats restants sans rien faire. Donc close() ne peut pas être appelé pour éviter de faire des itérations inutiles. Que vous pensiez que cela vaut la peine d'économiser ces cycles d'horloge est subjectif, je suppose, mais vous pourriez argumenter dans le sens de "si ce n'est pas nécessaire, ne le faites pas".

  3. En parcourant les commits de sourceforge, la fonctionnalité a été ajoutée au tronc par ce commit en 2007 et il semble que cette section de connections.py n'a pas changé depuis. C'est une fusion basée sur ce commit , qui contient le message

    Et le code que vous citez n'a jamais changé depuis.

    Cela incite ma dernière réflexion - c'est probablement juste une première tentative / un prototype qui vient de fonctionner et qui n'a donc jamais été modifié.

Version plus moderne

Vous créez un lien vers la source d'une version héritée du connecteur. Je note qu'il existe un fork plus actif de la même bibliothèque ici , auquel je renvoie dans mes commentaires sur la "nouvelle version" au point 1.

Notez que la version la plus récente de ce module a implémenté __enter__() et __exit__() dans cursor lui-même :voir ici . __exit__() ici fait appelez self.close() et peut-être que cela fournit un moyen plus standard d'utiliser la syntaxe with, par exemple

with conn.cursor() as c:
    #Do your thing with the cursor

Notes de fin

N. B. Je suppose que je devrais ajouter, pour autant que je comprenne la collecte des ordures (pas un expert non plus) une fois qu'il n'y a aucune référence à conn , il sera désaffecté. À ce stade, il n'y aura aucune référence à l'objet curseur et il sera également désalloué.

Cependant appelant cursor.close() ne signifie pas qu'il sera ramassé. Il brûle simplement les résultats et définit la connexion sur None . Cela signifie qu'il ne peut pas être réutilisé, mais il ne sera pas ramassé immédiatement. Vous pouvez vous en convaincre en appelant manuellement cursor.close() après votre with bloquer puis, disons, imprimer un attribut de cursor

N. B. 2 Je pense que c'est une utilisation quelque peu inhabituelle du with syntaxe comme conn l'objet persiste car il est déjà dans la portée externe - contrairement, par exemple, au with open('filename') as f: où il n'y a pas d'objets suspendus avec des références après la fin du with bloquer.