Почему диспетчер контекста MySQLdb Connection не закрывает курсор?
MySQLdbConnections
есть элементарный менеджер контекста, который создает курсор навойтилибо откатывается, либо фиксируется навыходи неявно не подавляет исключения. ОтИсточник подключения:
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()
Итак, кто-нибудь знаетЗачем курсор не закрывается при выходе?
Сначала я предположил, что это потому, что закрытие курсора ничего не делает, и что у курсоров есть только метод close в сравнении сPython DB API (см. комментарии кэтот ответ). Однако факт заключается в том, что закрытие курсора прожигает оставшиеся наборы результатов, если таковые имеются, и отключает курсор. Отисточник курсора:
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection: return
while self.nextset(): pass
self.connection = None
Было бы так просто закрыть курсор при выходе, поэтому я должен предположить, что это не было сделано специально. С другой стороны, мы можем видеть, что когда курсор удаляется, он все равно закрывается, поэтому я предполагаю, что сборщик мусора в конечном итоге дойдет до него. Я не знаю много о сборке мусора в Python.
def __del__(self):
self.close()
self.errorhandler = None
self._result = None
Другое предположение состоит в том, что может возникнуть ситуация, когда вы захотите повторно использовать курсор послеwith
блок. Но я не могу придумать причину, по которой вам нужно это сделать. Разве вы не можете всегда использовать курсор внутри его контекста и просто использовать отдельный контекст для следующей транзакции?
Чтобы быть очень ясным, этот пример, очевидно, не имеет смысла:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Так должно быть:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Этот пример также не имеет смысла:
# 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()
Это должно быть просто:
# first transaction
with conn as cursor:
cursor.execute(update_stmt_1)
# second transaction, new cursor
with conn as cursor:
cursor.execute(update_stmt_2)
Опять же, что может быть вредом при закрытии курсора при выходе и какие преимущества дает его не закрывать?