SQLite中的文件锁
我正在写我的第一个SQLAlchemy (0.6.8)/Python (2.7.1)程序,使用的是SQLite (3.7.6.3,应该是这个版本),在Windows Vista上运行。
为了进行单元测试,我把SQLite指向一个测试数据库,而我的单元测试脚本会定期删除这个数据库文件,这样我就可以一直在一个已知的初始状态下工作。
有时候,我的(单线程)单元测试无法删除这个文件:
WindowsError: [Error 32] The process cannot access the file because it is being used by another process
使用这个文件的唯一进程就是单元测试的框架。显然,有一个锁没有被我完成的单元测试释放,这导致同一个进程中的下一个单元测试无法删除这个文件。
我已经检查了我创建会话的所有地方,并确认每个地方都有对应的session.commit()或者session.rollback()。
我还在代码中查找了所有的session.commit()和session.rollback()调用,并在它们后面加上了session.close(),试图明确释放任何事务锁,但这并没有解决问题。
有没有什么诀窍可以确保在事务结束时移除剩余的锁,以便允许删除文件呢?
2 个回答
你在做单元测试的时候需要共享数据库吗?如果不需要的话,可以使用内存中的SQLite数据库来进行测试。从SQLAlchemy的文档来看:
如果没有指定文件路径,sqlite :memory: 是默认的选择。只需要指定sqlite://,其他的都不用加:
# in-memory database e = create_engine('sqlite://')
这样就不需要管理临时文件,也不用担心锁的问题,确保每次单元测试之间都是干净的环境等等。
有人遇到过类似的问题:http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg20724.html
你应该在建立连接的时候使用一个叫做 NullPool 的东西,这样可以确保在你调用 session.close()
后,没有任何活跃的连接会留下来。
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool
to_engine = create_engine('sqlite:///%s' % temp_file_name, poolclass=NullPool)
参考资料:http://www.sqlalchemy.org/docs/06/core/pooling.html?highlight=pool#sqlalchemy.pool
这个做法在 SQLAlchemy 0.7.0 之前是必须的。从 0.7.0 开始,这个行为就成了 SQLite 的默认设置。参考资料:http://www.sqlalchemy.org/docs/core/pooling.html?highlight=pool#sqlalchemy.pool