为什么 .fetchall() 调用解锁我的 SQLite3 数据库?

why a .fetchall() call unlock my sqlite3 database?

提问人:Rafael Romero 提问时间:7/9/2023 更新时间:7/9/2023 访问量:65

问:

我快要疯了,试图解决这个问题。运行以下代码后,我无法删除数据库的另一个表,并出现错误“数据库已锁定”。这是锁定我的数据库的代码:

con = sqlite3.connect('db/db.sqlite3')
cur=con.cursor()
query=f"SELECT * FROM data_temp LIMIT 1;"
res=cur.execute(query)
con.close()

我解决了包括一行来读取结果的问题:

con = sqlite3.connect('db/db.sqlite3')
cur=con.cursor()
query=f"SELECT * FROM data_temp LIMIT 1;"
res=cur.execute(query)
out=res.fetchall()  #<-------
con.close()

不知道为什么会这样......有人知道吗?

python 数据库 sqlite 锁定

评论


答:

0赞 Martin 7/9/2023 #1

您遇到“数据库已锁定”错误的原因与SQLite处理数据库连接和事务的方式有关。

当您在 SQLite 中使用 execute() 执行查询时,它会隐式启动事务。事务在提交或回滚之前一直处于活动状态。如果您没有显式提交或回滚事务,SQLite 会将其保持打开状态。

在第一个代码片段中,您正在执行查询,但不提取结果。由于事务仍处于打开状态,因此在事务完成之前,数据库连接将被锁定。

通过在执行查询后添加 res.fetchall() 或任何其他 fetch 方法(例如 res.fetchone()),您将使用查询结果。此操作向 SQLite 发出信号,表明您已完成对结果的处理,并允许完成事务。

事务完成后,将解除对数据库连接的锁定,您可以执行其他操作,例如删除表。

为确保数据库连接始终正确关闭,建议在使用 SQLite 连接时使用上下文管理器(带语句)。这样可以确保即使发生异常,连接也会关闭。下面是使用上下文管理器的代码的更新版本:

query = "SELECT * FROM data_temp LIMIT 1;"

with sqlite3.connect('db/db.sqlite3') as con:
    cur = con.cursor()
    cur.execute(query)
    out = cur.fetchall()

通过使用 with 语句,一旦退出块,连接就会自动关闭,即使引发了异常也是如此。这有助于防止数据库锁定问题。

评论

0赞 Rafael Romero 8/6/2023
嗨,马丁,我没有足够的声誉来投票给你的答案,但它非常有帮助!谢谢!