在Python中使用sqlite是否需要关闭游标?

时间:2010-02-24 23:02:16

标签: python sqlite

以下是该方案。在您的函数中,您使用游标执行语句,但其中一个失败并抛出异常。在关闭正在使用的光标之前,您的程序退出该函数。光标是否会占用空间?我必须关闭光标吗?

此外,Python文档中有一个游标使用示例,并说:“如果完成游标,我们也可以关闭游标。”关键字是“可以”,而不是“必须”。他们究竟是什么意思呢?

6 个答案:

答案 0 :(得分:17)

这可能是一个好主意(虽然它与sqlite无关,但不知道那里,但它会让你的代码更便携)。此外,最近的Python(2.5+),很容易:

from __future__ import with_statement
from contextlib import closing

with closing(db.cursor()) as cursor:
    # do some stuff

答案 1 :(得分:8)

您没有义务在光标上拨打close();它可以像任何其他对象一样被垃圾收集。

但是即使等待垃圾收集听起来没问题,我认为仍然可以确保数据库游标等资源无论是否存在异常都是好的风格。

答案 2 :(得分:7)

我还没有看到对sqlite3.Cursor.close()操作有任何影响。

关闭后,您仍然可以调用fetch(all|one|many),这将返回上一个执行语句中的剩余结果。即使正在运行Cursor.execute()仍有效......

答案 3 :(得分:4)

有趣的是,Python 3.0 doc表示"我们也可以关闭光标,如果我们已经完成了#34;,而Python 2.73.6 doc说&#34 ;如果我们完成了它,我们也可以关闭连接

Python 2.7和3.0-3.4文档没有描述游标.close()方法。但Python 3.5和3.6文档描述了cursor .close()方法:

  

立即关闭光标(而不是在调用__del__时)。

     

从这一点开始,光标将无法使用;如果使用光标尝试任何操作,将引发ProgrammingError异常。

答案 4 :(得分:1)

全部

我使用sqlite3的代码(Python 3.8)遇到了逐渐的内存泄漏。我将可能的原因追溯到我的数据库类。事实证明,我会打开并使用游标,但从未关闭过它。在程序运行期间,该数据库保持打开状态(Windows服务),并且在退出时将关闭。

一旦我开始在所有使用它们的数据库操作中关闭游标,我的内存泄漏就停止了,内存占用量变得稳定了。

因此,我建议您花些时间关闭游标。它使代码更加一致,而且显然可以帮助控制内存消耗。

以下是我如何关闭光标的示例:

def write_to_db(self, cache_item:CacheEntry):
        '''Write a single cache entry to the database'''
        crsr = self._db_con.cursor()

        # Load some data elements
        fax_line_path = cache_item._dir_part
        phone_line = cache_item._phone_line
        sub_folder = cache_item._subfolder
        fname = cache_item._fname
        work_done = cache_item.get_workdone()

        try:
            crsr.execute(FilenameCacheDB.INSERT_CACHE,
                             (fax_line_path, 
                              phone_line, 
                              sub_folder, 
                              fname, 
                              work_done))

        except Exception as e:
            LOG.warning(f"Could not write {cache_item} to db because {e}")
            raise e

        finally:
            #
            # I was *not* closing the cursor prior
            #
            crsr.close()
            self._db_con.commit()

答案 5 :(得分:0)

看看stackoverflowuser2010和Peer给出的代码片段和想法,使用Python contextmanager轻松处理游标变得容易。

from contextlib import contextmanager

@contextmanager
def OpenCursor(conn):
    cursor = conn.cursor()
    try:    
        yield (cursor)
    except Exception as e:  
        cursor.close()  
        raise e
    else:                     
        cursor.close() 

不使用OpenCursor的用法:

def get(conn, key, default=None):
    cursor = conn.cursor()
    cursor.execute(f'SELECT value FROM table WHERE key=?', (key,))
    row = cursor.fetchone()
    if row:
        return (True)
    else:
        return (default)

使用OpenCursor作为上下文管理器:

def get(conn, key, default=None):
    with OpenCursor(conn) as cursor:
        cursor.execute(f'SELECT value FROM table WHERE key=?', (key,))
        row = cursor.fetchone()
        if row:
            return (True)
        else:
            return (default)