Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Por que o gerenciador de contexto MySQLdb Connection não fecha o cursor?


Para responder à sua pergunta diretamente:não vejo nenhum mal em fechar no final de um with quadra. Não posso dizer por que não é feito neste caso. Mas, como há uma escassez de atividades sobre essa questão, fiz uma pesquisa no histórico do código e vou lançar alguns pensamentos (suposições ) sobre por que o close() pode não ser chamado:

  1. Há uma pequena chance de girar as chamadas para nextset() pode lançar uma exceção - possivelmente isso foi observado e visto como indesejável. Pode ser por isso que a versão mais recente do cursors.py contém esta estrutura em 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. Existe o potencial (um tanto remoto) de que pode levar algum tempo para percorrer todos os resultados restantes sem fazer nada. Portanto close() pode não ser chamado para evitar fazer algumas iterações desnecessárias. Se você acha que vale a pena salvar esses ciclos de clock é subjetivo, suponho, mas você pode argumentar como "se não for necessário, não faça".

  3. Navegando pelos commits do sourceforge, a funcionalidade foi adicionada ao trunk por este commit em 2007 e parece que esta seção de connections.py não mudou desde então. Essa é uma mesclagem baseada em este commit , que tem a mensagem

    E o código que você cita nunca mudou desde então.

    Isso leva ao meu pensamento final - provavelmente é apenas uma primeira tentativa / protótipo que funcionou e, portanto, nunca foi alterado.

Versão mais moderna


Você vincula à origem para uma versão herdada do conector. Observo que há um fork mais ativo da mesma biblioteca aqui , que vinculo em meus comentários sobre "versão mais recente" no ponto 1.

Observe que a versão mais recente deste módulo implementou __enter__() e __exit__() dentro do cursor em si:veja aqui . __exit__() aqui faz chamar self.close() e talvez isso forneça uma maneira mais padrão de usar a sintaxe, por exemplo.
with conn.cursor() as c:
    #Do your thing with the cursor

Notas finais


N.B. Acho que devo adicionar, até onde eu entendo, coleta de lixo (também não sou especialista) uma vez que não há referências a conn , ele será desalocado. Neste ponto, não haverá referências ao objeto cursor e ele também será desalocado.

No entanto chamando cursor.close() não significa que será coletado como lixo. Ele simplesmente grava os resultados e define a conexão como None . Isso significa que não pode ser reutilizado, mas não será coletado imediatamente. Você pode se convencer disso chamando manualmente cursor.close() depois do seu with bloco e então, digamos, imprimir algum atributo de cursor

N.B. 2 Eu acho que este é um uso um tanto incomum do with sintaxe como conn objeto persiste porque já está no escopo externo - ao contrário, digamos, do mais comum with open('filename') as f: onde não há objetos pendurados com referências após o final do with quadra.