显式游标的必要性。close()

2024-05-18 21:40:04 发布

您现在位置:Python中文网/ 问答频道 /正文

有时,我使用^{}而不是ORM执行原始查询(因为它绝对不是银弹)。

我注意到在一些地方,我在处理完数据库之后不会调用explicitcursor.close()。到目前为止,这还没有导致任何错误或性能问题。我想知道如果不显式地关闭游标,可能会有什么问题,什么会出错?

据我所知,Django中的connectioncursor遵循“Python数据库API规范v2.0”(PEP-249)。根据它,只要调用__del__()方法,cursor就会自动关闭。我想问题也可能是:当它没有被调用时,是否有用例?

仅供参考,我使用的是Python2.7和Django1.6.5。


Tags: django规范api数据库close地方错误orm
3条回答

__del__/.close()

  1. __del__不能保证被调用
  2. 有些数据库在其__del__中不调用cursor.close()(错误做法,但正确)
  3. 有些数据库实际上并不在connection函数中创建连接,而是在cursor函数中创建连接(例如,对于2&3:pyhive的presto[可能他们已经修补了它])

一般在服务器连接上

大多数服务器都有一个空闲超时配置属性(我们称之为T)。如果连接空闲时间超过T秒,服务器将删除该连接。大多数服务器还具有设置工作线程池(W)大小的属性。如果您已经有W个连接到服务器,则在尝试新连接时可能会挂起。再想象一下,您没有显式关闭连接的选项。在这种情况下,必须将超时设置为足够小,以使工作池永远不会完全使用,这是您有多少并发连接的函数。

但是,如果您确实关闭了游标/连接(即使不等同于上面的[3],它们的行为也类似),那么您不必管理这些服务器配置属性,您的线程池只需足够大,就可以管理所有并发连接(可以选择偶尔等待新资源)。我见过一些服务器(如卡桑德拉的Titan)无法从线程池中的工作人员不足中恢复,因此整个服务器会一直停机直到重新启动。

TL/DR 如果您使用的是非常完善的库,比如dano提到的库,那么就不会有问题。如果您使用的是不太原始的库,那么如果您不调用.close(),则可能会在服务器上阻塞获取工作线程,这取决于您的服务器配置和访问率。

虽然通常可以依赖操作系统来释放资源,但关闭数据库连接之类的东西以确保在不再需要资源时释放资源始终是良好的卫生习惯,从数据库的角度来看,真正重要的是确保任何更改都是commit()ed

Django的cursor类只是底层DB的cursor的包装,因此保持cursor打开的效果基本上与底层DB驱动程序相关。

根据psycopg2(psycopg2是Django用于PostgreSQL数据库的数据库驱动程序)FAQ,它们的游标是轻量级的,但会缓存使用游标对象进行查询时返回的数据,这可能会浪费内存:

Cursors are lightweight objects and creating lots of them should not pose any kind of problem. But note that cursors used to fetch result sets will cache the data and use memory in proportion to the result set size. Our suggestion is to almost always create a new cursor and dispose old ones as soon as the data is not required anymore (call close() on them.) The only exception are tight loops where one usually use the same cursor for a whole bunch of INSERTs or UPDATEs.

Django使用MySQLdb作为MySQL的后端,MySQL有几种不同类型的游标,包括一些实际将结果集存储在服务器端的游标。^{} documentation for ^{}指出,在完成这些操作后,关闭服务器端光标非常重要:

If you are using server-side cursors, it is very important to close the cursor when you are done with it and before creating a new one.

但是,这与Django无关,因为它使用由MySQLdb提供的默认Cursor类,该类在客户端存储结果。打开已使用的游标只会浪费存储结果集使用的内存,就像psycopg2。光标上的^{} method只会删除对db连接的内部引用,并耗尽存储的结果集:

def close(self):
    """Close the cursor. No further queries will be possible."""
    if not self.connection: return
    while self.nextset(): pass
    self.connection = None

从它们的源代码可以看出,Django使用的所有剩余后端(cx_oraclesqlite3/pysqlite2)都遵循相同的模式;通过删除/重置存储的结果/对象引用来释放内存。sqlite3 docs甚至没有提到Cursor有一个close方法,它只在包含的示例代码中偶尔使用。

当对cursor对象调用__del__()时,cursor将被关闭,这是正确的,因此,如果要长期保持对cursor的引用(例如,作为类的实例方法而保留的self.cursor对象),则只需要显式关闭。

相关问题 更多 >

    热门问题