返回 2026-06-23
🛠 工具 / 开源

sqlite-utils 4.0rc1 新增迁移和嵌套事务功能sqlite-utils 4.0rc1 adds migrations and nested transactions

simonwillison.net·2026-06-21

sqlite-utils 作为一个结合了 Python 库和 CLI 工具的 SQLite 数据库管理工具,发布了 4.0rc1 版本。新版本在 Python 默认的 sqlite3 包之上,引入了对复杂数据表转换、自动建表等高级操作的支持。此次更新的核心亮点是增加了数据库迁移和嵌套事务处理能力,大幅提升了开发者的数据库管理效率。

Simon Willison

2026年6月21日

sqlite-utils 是我开发的一个用于操作 SQLite 数据库的 Python 库和命令行工具组合。它在 Python 默认的 sqlite3 包之上提供了一系列广泛的高级操作,包括支持复杂的表结构转换、从 JSON 数据自动创建表等等。

我发布了 sqlite-utils 4.0rc1,这是 sqlite-utils v4 的首个候选发布版本(RC)。主版本号的提升意味着存在一些(微小的)向后不兼容的更改,因此我希望在正式发布稳定版之前,能让大家先试用一下。

新特性:数据库迁移(migrations)

与之前的 4.0 alpha 版本相比,此候选版本包含两项重要的新特性。

第一项是对数据库迁移的支持。这并非一个全新的实现——它是我几年前发布的 sqlite-migrate 包经过稍微修改的移植版本。我认为那个包已经经受住了时间的考验,所以我现在准备好将它直接内置到 sqlite-utils 中。

以下是在 migrations.py 文件中定义一组迁移操作的样子:

from sqlite_utils import Database, Migrations

migrations = Migrations("creatures")

@migrations()
def create_table(db):
    db["creatures"].create(
        {"id": int, "name": str, "species": str},
        pk="id",
    )

@migrations()
def add_weight(db):
    db["creatures"].add_column("weight", float)

这里定义了两个迁移操作,一个用于创建 creatures 表,另一个用于向该表添加列。

随后,你可以使用 Python 来运行这些迁移:

db = Database("creatures.db")
migrations.apply(db)

或者通过命令行的 migrate 命令来运行:

sqlite-utils migrate creatures.db migrations.py

该系统特意设计得很轻量:它不提供反向迁移,因此你所犯的任何错误都应该通过部署一个新的迁移来撤销它们以进行修复。

它的前身已经被 LLM 和其他各种项目使用了几年,因此我相信其设计是稳定且运行良好的。

新的迁移特性文档请见此处。

新特性:db.atomic() 事务

这个特性比迁移特性的使用频率要少得多,因此它值得测试人员投入更多关注。

以前,sqlite-utils 主要通过直接复用 sqlite3 机制的 `with db.conn:` 结构,将事务管理留给用户自己处理。

SQLite 以保存点(savepoints)的形式支持嵌套事务,因此我希望有一种抽象能让它们的使用变得尽可能简单。

我借鉴了 Django 和 Peewee 中的“atomic”术语。以下是新 API 的样子:

with db.atomic():
    db.table("dogs").insert({"id": 1, "name": "Cleo"}, pk="id")
    try:
        with db.atomic():
            db.table("dogs").insert({"id": 2, "name": "Pancakes"})
            raise ValueError("skip this one")
    except ValueError:
        pass
    db.table("dogs").insert({"id": 3, "name": "Marnie"})

更多细节请参阅文档。

向后不兼容的更改

v4 中向后不兼容的更改已在 alpha 版本的发行说明中描述。对于 4.0a0:

Upsert 操作现在在所有高于 3.23.1 的 SQLite 版本上使用 SQLite 的 INSERT ... ON CONFLICT SET 语法。对于依赖于之前 INSERT OR IGNORE 后跟 UPDATE 行为的应用程序来说,这是一个非常微小的破坏性更改。(#652) Python 库用户可以通过向 Database() 构造函数传递 use_old_upsert=True 来选择使用之前的实现,请参阅使用 INSERT OR IGNORE 的替代 upsert。 放弃了对 Python 3.8 的支持,增加了对 Python 3.13 的支持。(#646) sqlite-utils tui 现在由 sqlite-utils-tui 插件提供。(#648) 测试套件现在也会针对 SQLite 3.23.1(即添加新 INSERT ... ON CONFLICT SET 语法之前的最后一个版本,发布于 2018-04-10)运行。(#654)

而对于 4.0a1:

破坏性变更:db.table(table_name) 方法现在仅适用于表。要访问 SQL 视图,请改用 db.view(view_name)。(#657) table.insert_all() 和 table.upsert_all() 方法现在可以接受列表或元组的迭代器,作为字典的替代方案。第一项应为列名的列表/元组。详情请参阅“从列表或元组迭代器插入数据”。(#672) 破坏性变更:默认浮点列类型已从 FLOAT 更改为 REAL,这是浮点值的正确 SQLite 类型。这会影响插入数据时自动检测的列。(#645) 现在使用 pyproject.toml 代替 setup.py 进行打包。(#675) Python API 中的表现在能更好地记住首次创建时的主键和其他模式详细信息。(#655) 破坏性变更:table.convert() 和 sqlite-utils convert 机制不再跳过求值为 False 的值。以前需要 --skip-false 选项,现已移除。(#542) 破坏性变更:此库创建的表现在在模式中用“双引号”包裹表名和列名。以前它们使用[方括号]。(#677) --functions CLI 参数除了接受包含 Python 代码的字符串外,现在还可以接受 Python 文件的路径。此外,现在还可以多次指定该参数。(#659) 破坏性变更:导入 CSV 或 TSV 数据时,类型检测现在是 insert 和 upsert CLI 命令的默认行为。以前,除非传递 --detect-types 标志,否则所有列均被视为 TEXT。使用新的 --no-detect-types 标志可恢复旧行为。SQLITE_UTILS_DETECT_TYPES 环境变量已被移除。(#679)

试用一下

你可以像这样安装新的 RC 版本:

pip install sqlite-utils==4.0rc1

或者像这样使用 uvx 直接尝试 CLI 版本:

uvx --with sqlite-utils==4.0rc1 sqlite-utils --help

欢迎在 sqlite-utils Discord 频道与我们交流,或者在 GitHub Issues 中提交任何 bug。

需要完整排版与评论请前往来源站点阅读。