sqlite-utils 4.0rc1 新增迁移和嵌套事务
摘要
sqlite-utils 4.0rc1 是一个候选发布版本,新增了内置数据库迁移(从 sqlite-migrate 移植而来)以及通过 db.atomic() 实现的嵌套事务,同时包含少量不向后兼容的更改。
暂无内容
查看缓存全文
缓存时间: 2026/06/22 01:28
# sqlite-utils 4.0rc1 新增迁移和嵌套事务支持
来源:https://simonwillison.net/2026/Jun/21/sqlite-utils-40rc1/
2026年6月21日
sqlite-utils (https://sqlite-utils.datasette.io/en/latest/) 是我开发的一个用于操作 SQLite 数据库的 Python 库和命令行工具。它在 Python 默认的 sqlite3 包 (https://docs.python.org/3/library/sqlite3.html) 之上提供了大量高级操作,包括支持复杂表转换 (https://sqlite-utils.datasette.io/en/latest/cli.html#transforming-tables)、从 JSON 数据自动创建表 (https://sqlite-utils.datasette.io/en/latest/cli.html#inserting-json-data) 等等。
我发布了 sqlite-utils 4.0rc1 (https://sqlite-utils.datasette.io/en/latest/changelog.html#rc1-2026-06-21),这是 sqlite-utils v4 的第一个候选发布版。主版本号的提升意味着一些(次要的)不向后兼容的变更,所以我希望大家在正式稳定版发布前尝试一下。
#### 新功能:迁移
这个候选版相比之前的 4.0 alpha 版本有两个重要的新功能。
第一个是支持**数据库迁移**。这并不是一个全新的实现,它是几年前我发布的 sqlite-migrate (https://github.com/simonw/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 (https://llm.datasette.io/) 以及其他多个项目使用了数年,所以我对这个设计稳定且运行良好有信心。
新的迁移功能文档在此 (https://sqlite-utils.datasette.io/en/latest/migrations.html)。
#### 新功能:db.atomic() 事务
这个功能比迁移使用得更少,因此需要测试者更多的关注。
以前,`sqlite-utils` 主要通过 `with db.conn:` 结构将事务管理交给用户,直接复用 `sqlite3` 机制。
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"})
```
更多详情请参考文档 (https://sqlite-utils.datasette.io/en/latest/python-api.html#transactions-with-db-atomic)。
#### 不向后兼容的变更
v4 中的不向后兼容变更已在 alpha 发布说明中描述。对于 4.0a0 (https://sqlite-utils.datasette.io/en/latest/changelog.html#a0-2025-05-08):
> - 现在,在 3.23.1 以上所有 SQLite 版本中,upsert 操作使用 SQL 的 `INSERT ... ON CONFLICT SET` 语法。对于依赖之前 `INSERT OR IGNORE` 后跟 `UPDATE` 行为的应用程序来说,这是一个非常轻微的破坏性变化。(#652 (https://github.com/simonw/sqlite-utils/issues/652))
> - Python 库用户可以通过向 `Database()` 构造函数传入 `use_old_upsert=True` 来选择使用之前的实现,详情请参见使用 INSERT OR IGNORE 的替代 upsert 方法 (https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-old-upsert)。
> - 停止支持 Python 3.8,新增对 Python 3.13 的支持。(#646 (https://github.com/simonw/sqlite-utils/issues/646))
> - `sqlite-utils tui` 现在由 sqlite-utils-tui (https://github.com/simonw/sqlite-utils-tui) 插件提供。(#648 (https://github.com/simonw/sqlite-utils/issues/648))
> - 测试套件现在也会针对 SQLite 3.23.1(2018-04-10 发布,是添加新 `INSERT ... ON CONFLICT SET` 语法之前的最后一个版本)运行。(#654 (https://github.com/simonw/sqlite-utils/issues/654))
对于 4.0a1 (https://sqlite-utils.datasette.io/en/latest/changelog.html#a1-2025-11-23):
> - **破坏性变更**:`db.table(table_name)` 方法现在只适用于表。要访问 SQL 视图,请改用 `db.view(view_name)`。(#657 (https://github.com/simonw/sqlite-utils/issues/657))
> - `table.insert_all()` 和 `table.upsert_all()` 方法现在可以接受一个由列表或元组组成的迭代器,替代字典。第一个元素应该是列名的列表/元组。详情请参见从列表或元组迭代器插入数据 (https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-insert-lists)。(#672 (https://github.com/simonw/sqlite-utils/issues/672))
> - **破坏性变更**:默认浮点数列类型已从 `FLOAT` 更改为 `REAL`,这是 SQLite 中浮点值的正确类型。这会影响插入数据时自动检测的列。(#645 (https://github.com/simonw/sqlite-utils/issues/645))
> - 现在使用 `pyproject.toml` 替代 `setup.py` 进行打包。(#675 (https://github.com/simonw/sqlite-utils/issues/675))
> - Python API 中的表现在在记住首次创建时的主键和其他模式细节方面做得更好了。(#655 (https://github.com/simonw/sqlite-utils/issues/655))
> - **破坏性变更**:`table.convert()` 和 `sqlite-utils convert` 机制不再跳过计算结果为 `False` 的值。之前需要 `--skip-false` 选项,现已移除。(#542 (https://github.com/simonw/sqlite-utils/issues/542))
> - **破坏性变更**:此库创建的表现在模式中使用双引号包裹表名和列名(`"double-quotes"`)。之前它们使用方括号(`[square-braces]`)。(#677 (https://github.com/simonw/sqlite-utils/issues/677))
> - `--functions` CLI 参数现在除了接受一个包含 Python 代码的字符串外,还可以接受一个 Python 文件的路径。现在也可以多次指定该参数。(#659 (https://github.com/simonw/sqlite-utils/issues/659))
> - **破坏性变更**:在导入 CSV 或 TSV 数据时,`insert` 和 `upsert` CLI 命令现在默认启用类型检测。以前所有列都被视为 `TEXT`,除非传递了 `--detect-types` 标志。使用新的 `--no-detect-types` 标志可以恢复旧的行为。已移除 `SQLITE_UTILS_DETECT_TYPES` 环境变量。(#679 (https://github.com/simonw/sqlite-utils/issues/679))
#### 尝试一下
你可以这样安装新的候选版:
```
pip install sqlite-utils==4.0rc1
```
或者直接使用 `uvx` 尝试命令行版本:
```
uvx --with sqlite-utils==4.0rc1 sqlite-utils --help
```
欢迎加入 sqlite-utils Discord 频道 (https://discord.gg/Ass7bCAMDw) 与我们讨论,或前往 GitHub Issues (https://github.com/simonw/sqlite-utils/issues) 提交任何错误报告。
相似文章
sqlite-utils 4.0rc1
sqlite-utils 4.0rc1 是 Python CLI 工具的一个发布候选版本,该工具简化了 SQLite 数据库操作。
SQLite 3.53.0
SQLite 3.53.0 发布,带来重要的累积改进,包括 ALTER TABLE 约束修改、新的 JSON 函数(json_array_insert),以及通过新的查询结果格式化库实现的重大 CLI 模式增强。
datasette 1.0a28
Datasette 1.0a28 alpha 版本修复了前一个 alpha 版本中发现的兼容性错误和资源管理问题,包括修复 execute_write_fn() 回调、数据库清理方法,以及新增用于测试中自动清理的 pytest 插件。
datasette 1.0a27
Datasette 1.0a27 发布,主要包含重大安全改进(现代化 CSRF 标头)、新增 RenameTableEvent 以增强插件兼容性,以及多项 API 增强,包括改进的 upsert 处理和数据库锁定修复。
datasette 1.0a29
Datasette 1.0a29 已发布,包含新的实用方法、对空表格的 UI 改进,以及在 Codex CLI 协助下修复的竞争条件等错误修复。