Python Windows关闭后移动sqlite3数据库时出错
下面是我的问题的一个简化示例:Python Windows关闭后移动sqlite3数据库时出错,python,windows,sqlite,Python,Windows,Sqlite,下面是我的问题的一个简化示例: import os import sqlite3 with sqlite3.connect('test.db.temp') as db: db.executescript('CREATE TABLE foo (bar);') os.rename('test.db.temp', 'test.db') 输出: > python test.py Traceback (most recent call last): File "test.py", l
import os
import sqlite3
with sqlite3.connect('test.db.temp') as db:
db.executescript('CREATE TABLE foo (bar);')
os.rename('test.db.temp', 'test.db')
输出:
> python test.py
Traceback (most recent call last):
File "test.py", line 7, in <module>
os.rename('test.db.temp', 'test.db')
WindowsError: [Error 32] The process cannot access the file because it is being used by another process
>python test.py
回溯(最近一次呼叫最后一次):
文件“test.py”,第7行,在
重命名('test.db.temp','test.db')
WindowsError:[错误32]该进程无法访问该文件,因为其他进程正在使用该文件
背景:我正在尝试以“原子”方式创建数据库,最简单的方法是在临时位置创建数据库,然后将其移动。问题是连接对象的上下文管理器似乎无法工作 通过这种方式工作:
db = sqlite3.connect('test.db.temp')
db.executescript('CREATE TABLE foo (bar);')
db.close()
os.rename('test.db.temp', 'test.db')
值得研究的是,为什么它首先实现了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
更新:从这个角度看,与SQLite一起使用时,它看起来像与
一起执行事务,因此您的代码类似于:
db = sqlite3.connect('test.db.temp')
db.begin_transaction()
db.executescript('CREATE TABLE foo (bar);')
db.commit()
os.rename('test.db.temp', 'test.db')
因此,在重命名数据库时,它显然仍然处于打开状态。建议的代码如下所示:
with contextlib.closing(sqlite3.connect('test.db.temp')) as db:
db.executescript('CREATE TABLE foo (bar);')
os.rename('test.db.temp', 'test.db')
问题是连接对象的上下文管理器似乎不起作用
通过这种方式工作:
db = sqlite3.connect('test.db.temp')
db.executescript('CREATE TABLE foo (bar);')
db.close()
os.rename('test.db.temp', 'test.db')
值得研究的是,为什么它首先实现了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
更新:从这个角度看,与SQLite一起使用时,它看起来像与
一起执行事务,因此您的代码类似于:
db = sqlite3.connect('test.db.temp')
db.begin_transaction()
db.executescript('CREATE TABLE foo (bar);')
db.commit()
os.rename('test.db.temp', 'test.db')
因此,在重命名数据库时,它显然仍然处于打开状态。建议的代码如下所示:
with contextlib.closing(sqlite3.connect('test.db.temp')) as db:
db.executescript('CREATE TABLE foo (bar);')
os.rename('test.db.temp', 'test.db')
根据,executescript创建一个游标对象。我猜光标对象不会立即被破坏。尝试在上下文管理器中显式创建游标:
with sqlite3.connect('test.db.temp') as db:
cur = db.cursor()
cur.execute('CREATE TABLE foo (bar);')
根据,executescript创建一个游标对象。我猜光标对象不会立即被破坏。尝试在上下文管理器中显式创建游标:
with sqlite3.connect('test.db.temp') as db:
cur = db.cursor()
cur.execute('CREATE TABLE foo (bar);')
如果是这种情况,那么正确的解决方法不是添加一个带有cur=
的。。。而不是希望它能早点关闭?(注意:我不知道SQLite的Python绑定。)我开始讨论这个例子:这个例子似乎很有趣,它在Xubuntu 14.04上工作,但在Windows7上不工作。必须添加显式db.close()才能在Windows.Interest上工作。无论文件是否已打开,重命名调用都应成功,因为Windows支持重命名当前正在使用的文件(进程的文件句柄未失效)。是的,很抱歉,与光标无关。事实上,它只是用sqlite3.connect('test.db.temp'):pass;重新编程;;os.rename('test.db.temp','test.db')
如果是这种情况,那么正确的修复方法不是用cur=
添加一个。。。而不是希望它能早点关闭?(注意:我不知道SQLite的Python绑定。)我开始讨论这个例子:这个例子似乎很有趣,它在Xubuntu 14.04上工作,但在Windows7上不工作。必须添加显式db.close()才能在Windows.Interest上工作。无论文件是否已打开,重命名调用都应成功,因为Windows支持重命名当前正在使用的文件(进程的文件句柄未失效)。是的,很抱歉,与光标无关。事实上,它只是用sqlite3.connect('test.db.temp'):pass;重新编程;;os.rename('test.db.temp','test.db')
编辑了您的答案,以包含contextlib.closing
:)sqlite api没有将文件作为contextmanager的一部分关闭,这真是太遗憾了。@AnthonySottile:很好,谢谢!我不知道contextlib
。将您的答案编辑为包含contextlib。关闭:)sqlite api没有将文件作为contextmanager的一部分关闭,真是太遗憾了。@AnthonySottile:很好,谢谢!我不知道contextlib
。