Por que o gerenciador de contexto do MySQLdb Connection não fecha o cursor?
MySQLdbConnections
ter um gerenciador de contexto rudimentar que cria um cursor ementrar, reverte ou confirma emSaída, e implicitamente não suprime exceções. DeFonte de conexão:
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()
Então, alguém sabeporque o cursor não está fechado na saída?
No começo, eu assumi que era porque fechar o cursor não fazia nada e que os cursores só tinham um método próximo em deferência aoAPI de banco de dados Python (veja os comentários paraesta resposta) No entanto, o fato é que o fechamento do cursor queima nos demais conjuntos de resultados, se houver, e desativa o cursor. Defonte do cursor:
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection: return
while self.nextset(): pass
self.connection = None
Seria tão fácil fechar o cursor na saída, por isso suponho que não tenha sido feito de propósito. Por outro lado, podemos ver que, quando um cursor é excluído, ele é fechado de qualquer maneira, então acho que o coletor de lixo acabará contornando. Eu não sei muito sobre coleta de lixo em Python.
def __del__(self):
self.close()
self.errorhandler = None
self._result = None
Outro palpite é que pode haver uma situação em que você deseja reutilizar o cursor após owith
quadra. Mas não consigo pensar em nenhum motivo para você precisar fazer isso. Você não pode sempre terminar de usar o cursor dentro de seu contexto e apenas usar um contexto separado para a próxima transação?
Para ser muito claro, este exemplo obviamente não faz sentido:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Deveria ser:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Este exemplo também não faz sentido:
# first transaction
with conn as cursor:
cursor.execute(update_stmt_1)
# second transaction, reusing cursor
try:
cursor.execute(update_stmt_2)
except:
conn.rollback()
else:
conn.commit()
Deve ser apenas:
# first transaction
with conn as cursor:
cursor.execute(update_stmt_1)
# second transaction, new cursor
with conn as cursor:
cursor.execute(update_stmt_2)
Novamente, qual seria o problema em fechar o cursor na saída e quais são os benefícios de não fechá-lo?