这是一段在Python 3.10.5上运行的代码-
with sqlite3.connect("test.db") as db:
cursor = db.cursor()
cursor.execute("""CREATE TABLE IF NOT EXISTS testtable(id integer PRIMARY KEY, name text);""")
cursor.execute("""INSERT INTO testtable(id, name) VALUES (1, "XYZ")""")
db.commit()
cursor.execute("select * from testtable")
for x in cursor.fetchall():
print(x)
现在,根据我对WITH语句工作方式的理解,与数据库的连接将在代码块末尾自动关闭,而不需要我显式调用
db.close()
,类似于文件I/O操作的处理方式。这意味着下一个 cursor.execute()
失败,因为它位于语句之外,因此无效。
但是,它仍然运行!我能够看到表的内容。这里发生了什么?
文件的上下文管理 (
with file(...) as x
) 会在退出块时自动关闭文件。然而,一般来说,开发人员可以自由地使用上下文来管理他们想要的任何操作。
在
sqlite3
的情况下,在 with
块中使用数据库连接对象会创建 数据库事务。这很有用,因为当 with
块正常退出时,事务会自动提交,或者如果出现异常,事务会自动回滚。连接本身不会在块结束时自动关闭。请参阅 sqlite3 文档 和相关的 过去的 StackOverflow 线程。
如果您希望连接自动关闭,请参阅glglgl的这个答案。
sqlite3.connect
不能用作自关闭上下文管理器(如文件)。
您可以使用生成的连接对象作为上下文管理器;请参阅 Python sqlite3 文档的这一部分,但要了解事务。
该文档还有此注释:
上下文管理器既不会隐式打开新事务,也不会关闭连接。如果您需要关闭上下文管理器,请考虑使用 contextlib.looking()。
所以尝试一下
import sqlite3
import contextlib
with contextlib.closing(sqlite3.connect("test.db")) as db:
cursor = db.cursor()
cursor.execute("""CREATE TABLE IF NOT EXISTS testtable(id integer PRIMARY KEY, name text);""")
cursor.execute("""INSERT INTO testtable(id, name) VALUES (1, "XYZ")""")
db.commit()
cursor.execute("select * from testtable")
for x in cursor.fetchall():
print(x)
这引发了这个异常:
Traceback (most recent call last):
File "/Users/evert/scratch/sqlitewith.py", line 12, in <module>
cursor.execute("select * from testtable")
sqlite3.ProgrammingError: Cannot operate on a closed database.