何时使用MySQLdb关闭游标
|
我正在构建WSGI Web应用程序,并且我有一个MySQL数据库。我正在使用MySQLdb,它提供了用于执行语句和获取结果的游标。获取和关闭游标的标准做法是什么?特别是,我的光标应持续多长时间?我应该为每个交易获取一个新的游标吗?
我相信您需要在提交连接之前关闭游标。查找不需要中间提交的事务集有什么显着的优势,这样您就不必为每个事务获取新的游标了吗?获取新的游标是否有很多开销,还是不重要?
没有找到相关结果
已邀请:
5 个回复
献导外拘
关键字是一个好主意,但是在这种特定情况下,它可能无法提供预期的功能。 从模块的1.2.5版本开始,
通过以下代码(github)实现上下文管理器协议:
现有一些关于
的问答,或者您可以阅读了解Python的\“ with \”语句,但是实质上发生的是
在
块的开始执行,而
在离开
块时执行。如果以后要引用该对象,则可以使用可选语法
将
返回的对象绑定到名称。因此,鉴于上述实现,这是查询数据库的一种简单方法:
现在的问题是,退出“ 0”块后连接和游标的状态是什么?上面显示的
方法仅调用
或
,而这些方法都没有继续调用
方法。游标本身未定义
方法-并没有关系,因为
仅管理连接。因此,退出“ 0”块后,连接和游标都保持打开状态。通过在上面的示例中添加以下代码,可以很容易地确认这一点:
您应该看到输出“光标已打开;连接已打开”输出到标准输出。 我相信您需要在提交连接之前关闭游标。 为什么? MySQL C API是
的基础,它没有实现任何游标对象,如模块文档中所暗示:\“ MySQL不支持游标;但是,游标很容易模拟。\”实际上,Indeed21ѭ类直接继承了从ѭ22开始,并且对游标的提交/回退没有任何限制。 Oracle开发人员曾这样说: cnx.commit()在cur.close()之前听起来对我来说最合逻辑。可能是你 可以遵循以下规则:\“如果不再需要关闭光标。\” 因此,在关闭游标之前,先执行commit()。最后, 连接器/ Python,并没有多大区别,但其他 数据库可能。 我希望这与您在该主题上达到“标准做法”一样近。 查找不需要中间提交的事务集有什么显着的优势,这样您就不必为每个事务获取新的游标了吗? 我对此非常怀疑,在尝试这样做时,您可能会引入其他人为错误。最好决定约定并坚持执行。 获取新的游标是否有很多开销,还是不重要? 开销可以忽略不计,完全不涉及数据库服务器。它完全在MySQLdb的实现中。如果您真的想知道创建新游标时发生了什么,可以在github上查看
。 回到前面讨论
时,也许现在您可以理解为什么
类
和
方法在每个
块中为您提供一个全新的游标对象,而不必理会它或最后将其关闭的块。它相当轻巧,纯粹是为了您的方便而存在。 如果对微管理光标对象确实很重要,则可以使用contextlib.closing来弥补光标对象没有定义
方法的事实。为此,还可以使用它在退出“ 0”块时强制连接对象自行关闭。这应该输出\“ my_curs已关闭; my_conn已关闭\”:
注意,
不会调用参数对象的
和
方法。它只会在
块的末尾调用参数对象的
方法。 (要查看实际情况,只需使用包含简单
语句的
,
和
方法定义类
,然后将执行
时发生的情况与执行
时发生的情况进行比较。)这有两个重要的含义: 首先,如果启用了自动提交模式,当您使用“ 45”并在块末尾提交或回滚该事务时,MySQLdb将在服务器上将“ 44”作为显式事务。这些是MySQLdb的默认行为,旨在保护您免受MySQL的立即提交任何DML语句的默认行为的影响。 MySQLdb假定使用上下文管理器时需要事务,并使用显式的“ 44”绕过服务器上的自动提交设置。如果您习惯使用
,您可能会认为自动提交实际上只是被绕过了而被禁用了。如果在代码中添加“ 48”并失去事务完整性,您可能会感到不快。您将无法回滚更改,您可能会开始看到并发错误,并且可能并不清楚为什么。 其次,与将新光标对象绑定到50的51相比,“ 49”将连接对象绑定到“ 50”。在后一种情况下,您将无法直接访问连接对象!取而代之的是,您将必须使用游标的
属性,该属性提供对原始连接的代理访问。关闭光标时,其“ 53”属性将设置为“ 55”。这将导致废弃的连接一直存在,直到发生以下情况之一: 删除所有对光标的引用 光标超出范围 连接超时 通过服务器管理工具手动关闭连接 您可以通过监视打开的连接(在Workbench中或使用
)并一一执行以下行来进行测试:
屠创氓读叔
席酱
语法在执行
块的主体之前调用上下文管理器的
方法,然后再执行其
方法。 连接有一个
方法,除了创建和返回游标外什么都不做;还有一个
方法,它可以提交或回滚(取决于是否引发异常)。它不会关闭连接。 PyMySQL中的游标纯粹是用Python实现的抽象。 MySQL本身没有等效的概念。1 游标具有不执行任何操作的
方法和“关闭”游标的
方法(这仅意味着使游标对其父连接的引用无效,并丢弃游标上存储的所有数据)。 游标保留对产生它们的连接的引用,但是连接不保留对它们创建的游标的引用。 连接采用a67ѭ方法将其关闭 根据https://docs.python.org/3/reference/datamodel.html,CPython(默认的Python实现)使用引用计数,并在对象的引用数量达到零时自动删除该对象。 将这些内容放在一起,我们会发现像这样的幼稚代码在理论上是有问题的:
问题是没有任何事情关闭连接。确实,如果将上面的代码粘贴到Python Shell中,然后在MySQL Shell中运行
,您将能够看到您创建的空闲连接。由于MySQL的默认连接数为151,这并不是很大,因此,如果您有许多使这些连接保持打开状态的进程,那么从理论上讲您可能会遇到问题。 但是,在CPython中,有一个节省的宽限期,可确保像我上面的示例一样的代码不会导致您遗漏打开的连接。节省的余地是,一旦
超出范围(例如,创建它的函数完成,或者
获得分配给它的另一个值),其引用计数将变为零,这将导致其引用被删除,从而断开连接\的引用计数为零,导致调用连接的“ 67”方法,该方法强制关闭连接。如果已经将上面的代码粘贴到Python shell中,那么现在可以通过运行
进行模拟;一旦这样做,打开的连接就会从from56ѭ输出中消失。 但是,仅依靠它是不明智的,并且在理论上可能会在CPython以外的Python实现中失败。从理论上讲,更清洁的方法是显式地对连接进行“ 75”连接(以释放数据库上的连接,而无需等待Python销毁对象)。这个更健壮的代码如下所示:
这很丑陋,但不依赖Python破坏对象来释放数据库连接(数量有限)。 请注意,如果您已经像这样显式关闭连接,则关闭游标完全没有意义。 最后,在这里回答次要问题: 获取新的游标是否有很多开销,还是不重要? 不,实例化一个游标根本不会影响MySQL,并且基本上什么也不做。 查找不需要中间提交的事务集有什么显着的优势,这样您就不必为每个事务获取新的游标了吗? 这是情境,很难给出普遍的答案。如https://dev.mysql.com/doc/refman/en/optimizing-innodb-transaction-management.html所述,“如果应用程序每秒提交数千次,则它可能会遇到性能问题,并且会出现不同的性能问题。如果仅每2-3小时提交一次”。您需要为每次提交支付性能开销,但是通过延长事务处理时间,会增加其他连接不得不花时间等待锁的机会,增加死锁的风险,并可能增加其他连接执行某些查找的成本。 1 MySQL确实具有调用游标的构造,但它们仅存在于存储过程中;它们与PyMySQL游标完全不同,因此与此处无关。
硕歌沙
关键是您可以将游标的执行结果存储在另一个变量中,从而释放游标以执行第二次执行。仅当您使用fetchone()时,您才会遇到这种问题,并且在遍历第一个查询的所有结果之前需要执行第二次游标执行。 否则,我要说的是,一旦完成将所有数据移出游标,请立即关闭游标。这样,您不必担心稍后在代码中捆绑松散的一端。
浆错