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()
import sqlite3
import contextlib
def execute_statement(statement):
with contextlib.closing(sqlite3.connect(path_to_file)) as conn: # auto-closes
with conn: # auto-commits
with contextlib.closing(conn.cursor()) as cursor: # auto-closes
cursor.execute(statement)
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)
首先,什么是Pythonsqlite3.Cursor?代码显示它本质上是sqlite3_stmt结构的持有者,passed to sqlite3_step是passed to sqlite3_step迭代结果行的预准备语句句柄。 就我所知,使用conn.cursor()创建您自己的Cursor对象,而不是仅仅使用为您自动创建并由conn.execute()返回的对象,是没有好处的。跳过conn.cursor(),每次都省去额外的代码行。(这是特定于SQLite的建议;我不知道是否有理由使用其他数据库系统的其他DB-API驱动程序创建您自己的游标。) cursor.close()做什么?
9条答案
按热度按时间jaql4c8m1#
这可能是个好主意(虽然它对于SQLite可能不是很重要,我不知道它在哪里,但它会使您的代码更可移植)。此外,使用最新的Python(2.5+),很容易做到:
ogsagwnx2#
您不必在游标上调用
close()
;它可以像任何其他对象一样被垃圾回收。但是,即使等待垃圾收集听起来没问题,我认为确保诸如数据库游标之类的资源被关闭(无论是否存在异常)仍然是一种不错的风格。
pgpifvop3#
全,
我在使用Sqlite3的代码(Python3.8)中遇到了逐渐的内存泄漏。我将可能的原因追溯到我的数据库类。事实证明,我会打开并使用光标,但从未关闭它。该数据库在程序(Windows服务)期间保持打开状态,在退出时将关闭。
一旦我开始在所有使用游标的数据库操作中关闭游标,我的内存泄漏就会停止,并且内存占用变得稳定。
因此,我建议您花时间关闭光标。它使代码更加一致,而且显然有助于控制内存消耗。
下面是我如何关闭光标的一个示例:
jv2fixgn4#
有趣的是,Python 3.0 doc说“如果我们完成它,我们也可以关闭它”,而Python 2.7和3.6文档说“如果我们完成它,我们也可以关闭*连接”。
Python2.7和3.0-3.4文档没有描述游标
.close()
方法。但Python3.5和3.6文档描述了游标.close()
方法:立即关闭光标(而不是每次调用
__del__
时)。从这一点开始,游标将不可用;如果尝试对游标执行任何操作,将引发
ProgrammingError
异常。uelo1irk5#
此代码将自动关闭
Cursor
。它还将自动关闭并提交Connection
。ppcbkaq56#
我还没有看到
sqlite3.Cursor.close()
操作的任何效果。关闭后,您仍然可以调用
fetch(all|one|many)
,它将返回上一条EXECUTE语句的剩余结果。即使运行Cursor.execute()
也能正常工作...3pvhb19x7#
查看Stackoverflow User2010和Peer提供的代码片段和想法,使用PythonConextManager可以更轻松地优雅地处理游标。
在不使用OpenCursor的情况下使用:
使用OpenCursor作为上下文管理器:
kr98yfug8#
是的,我们应该关闭我们的光标。我曾经在使用游标配置连接对象时遇到错误:‘Pragma Synchronous=Off’和‘Pragma JONERNAL_MODE=Off’以加快插入速度。一旦我关闭了光标,错误就消失了。我忘了我遇到了什么类型的错误。
0lvr5msh9#
首先,什么是Python
sqlite3.Cursor
?代码显示它本质上是sqlite3_stmt
结构的持有者,passed tosqlite3_step
是passed tosqlite3_step
迭代结果行的预准备语句句柄。就我所知,使用
conn.cursor()
创建您自己的Cursor对象,而不是仅仅使用为您自动创建并由conn.execute()
返回的对象,是没有好处的。跳过conn.cursor()
,每次都省去额外的代码行。(这是特定于SQLite的建议;我不知道是否有理由使用其他数据库系统的其他DB-API驱动程序创建您自己的游标。)cursor.close()
做什么?SQLite文档给出了
sqlite3_reset
的简短描述,stmt_reset
称之为:6.绑定参数和预准备语句的重用
…*SQLite允许多次评估相同的prepared statement版本。这是使用以下例程完成的:
在通过一次或多次调用sqlite3_step()对prepared statement进行求值之后,可以对其进行重置,以便通过对sqlite3_reset()的调用再次进行求值。可以将sqlite3_reset()看作是将prepared statement程序倒回到开头。
关闭游标会导致Python通知底层的SQLite库丢弃相关的结果集。但是,Python仍然保留
sqlite3_stmt
结构,因为它在内部维护已准备好的语句的缓存。如下所示的代码在CPython上通常很好用:
这是因为:
1.当迭代到达结果集末尾时,python会自动调用
stmt_reset
丢弃结果集。这发生在for … in …
和sqlite3.Cursor.fetch*
方法等标准的Python迭代协议中。1.如果循环提前退出,例如因为引发异常,CPython的引用计数将触发匿名游标对象的终结,再次调用
stmt_reset
。其他的Python实现可能有所不同。考虑到上述情况,虽然不关闭游标导致内存泄漏的可能性不大,但如果游标同时和,则绝对“有可能”:
因此,为了便于移植和明确,您可以这样写: