WindowsError 关闭后移动 sqlite3 数据库

WindowsError moving sqlite3 database after closing

这是我的问题的一个简化示例:

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

背景:我正在尝试以 "atomic" 方式创建数据库,最简单的方法是在临时位置创建数据库,然后移动它。

问题是连接对象的上下文管理器似乎不起作用。

这样操作:

db = sqlite3.connect('test.db.temp')
db.executescript('CREATE TABLE foo (bar);')
db.close()
os.rename('test.db.temp', 'test.db')

值得研究为什么它首先实现了 __enter__/__exit__...

更新: 从这个 answer 看来 with 与 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')

根据documentationexecutescript创建游标对象。我猜光标对象不会立即被销毁。尝试在上下文管理器中显式创建游标:

with sqlite3.connect('test.db.temp') as db:
    cur = db.cursor()
    cur.execute('CREATE TABLE foo (bar);')