Python 3.6.0的sqlite3模块无法执行VACUUM语句

Python 3.6.0的sqlite3模块存在一个bug(见issue 28518),无法执行VACUUM语句。Python 3.6.1已经修复这个bug

一执行就出现异常:

Traceback (most recent call last):
  File “D:\desktop\cannot_vacuum.py”, line 25, in <module>
    conn.execute(‘VACUUM’)
sqlite3.OperationalError: cannot VACUUM from within a transaction

 

这是因为在真正执行VACUUM之前,Python 3.6.0的sqlite3模块(自作主张地)添加了一条BEGIN语句创建了一个事务,而VACUUM不能在事务中执行。

 

在Python 3.6.0,要想让程序正常运行,需要在connect时设置isolation_level参数为None,如下:

conn = sqlite3.connect(‘test.db’, isolation_level=None)

或者这样做:

conn = sqlite3.connect(‘test.db’)
conn.isolation_level = None

 

查看文档和源码,isolation_level=None的作用:sqlite3模块在开始执行某些SQL语句之前,不再(智能地)自动BEGIN一个事务、或自动COMMIT上一个事务。用户须手动BEGIN一个事务、手动COMMIT之前的修改。

此时(isolation_level=None)程序完全遵照SQLite引擎的行为:在事务以外执行一条SQL语句之后,会立刻COMMIT修改

 

尽管sqlite3模块默认的“傻瓜模式”在绝大多数情况下工作良好,个人还是推荐尽量使用isolation_level=None,原因有三:

  1. 在个别复杂情况下,傻瓜模式有陷阱,不了解的人容易陷进去。issue 10740的讨论。
  2. sqlite3模块更透明,sqlite3引擎更简洁。喜欢这种风格。
  3. 同一代码在所有版本的Python 3都行得通。
点赞