MySQLdb Connections
具有简单的上下文管理器,当进入时创建一个游标,在退出时要么回滚要么提交,并且隐式地不会抑制异常。请参考连接源码:
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)
再次强调,关闭游标会有什么危害?不关闭游标有哪些好处?
MySQLdb
源代码相对较少地涉及底层_mysql
模块(作为.pyd
二进制文件与MySQLdb
一起分发),或者其实现的API。我倾向于认为,要么包的作者遇到了在这些依赖项中埋藏的原因,要么它开始时只是YAGNI,最终变成了“不破不立”。 - Air