sqlite-utils 4.0发布,引入数据库模式迁移功能
评分
77对于已有sqlite-utils使用经验的开发者,新功能细节有增量信息;但广为人知的背景信息较多。
文章结构清晰,包含代码示例、设计讨论和发布说明,质量高。
对使用sqlite-utils的开发者有直接实用价值,尤其是迁移和嵌套事务功能。
发布于2026年7月7日,非常及时。
作者是工具的原作者,信息可靠且权威。
基础分 85 × T2 信源权重 ×0.9 = 77
精选线 70已入选精选
精选理由
内容丰富且实用,详细介绍了迁移系统的设计思路和用法,并提供了与其他方案的比较。
AI 点评
「如果你是SQLite的深度用户,尤其是使用Datasette或LLM构建应用的开发者,这次更新绝对值得关注。迁移系统的加入让项目管理数据库模式变更变得更加安全和可追溯,而嵌套事务和复合外键的加入也填补了长期以来的功能缺口。」
速览
sqlite-utils 4.0 是该项目的第124个版本,也是自2020年3.0以来的首次大版本更新。主要新特性包括数据库模式迁移、嵌套事务(通过db.atomic()方法)和复合外键支持。迁移系统允许用户用Python文件定义一系列数据库变更,并通过命令行或Python API应用。此外还包含一些破坏性变更和CSV/TSV导入时自动检测列类型等功能。
- 引入数据库模式迁移系统,支持定义和执行一系列数据库变更。
- 新增嵌套事务支持,通过db.atomic()上下文管理器实现事务嵌套。
- 添加复合外键支持,包括创建、转换和内省。
- 包含破坏性变更,如upserts使用新的SQL语法,db.query()改为仅执行查询语句。
正文
今天早上我发布了 sqlite-utils 4.0,这是该项目的第124个版本,也是自2020年11月的 3.0 以来的首次主版本号提升。除了一些小而重要的破坏性变更(在 本升级指南 中描述)外,此版本引入了三个主要功能:数据库迁移、嵌套事务(通过新的 db.atomic() 方法)以及支持 复合外键。
使用 sqlite-utils 进行数据库模式迁移
模式迁移定义了对 SQLite 数据库进行的一系列更改,以及跟踪哪些迁移已应用并应用任何待处理迁移的机制。
迁移在 Python 文件中使用 sqlite-utils Python 库进行定义,该库包含一个强大的 table.transform() 方法,提供了 增强的 ALTER TABLE 功能,这些功能是 SQLite 的 ALTER TABLE 语句所不支持的。
(table.transform() 实现了 SQLite 文档推荐的模式——创建一个具有新模式的临时表,复制数据,然后删除旧表并将临时表重命名为原表。)
以下是一个示例迁移文件,它创建了一个名为 creatures 的表,在第二步中添加了一个额外的列,然后在第三步中更改了其中两列的类型:
from sqlite_utils import 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)
@migrations()
def change_column_types(db):
db["creatures"].transform(types={"species": int, "weight": str})
将其保存为 migrations.py,并在一个新数据库上像这样运行:
uvx sqlite-utils migrate data.db migrations.py
然后如果你检查该数据库的模式:
uvx sqlite-utils schema data.db
你会看到以下 SQL:
CREATE TABLE "_sqlite_migrations" (
"id" INTEGER PRIMARY KEY,
"migration_set" TEXT,
"name" TEXT,
"applied_at" TEXT
);
CREATE UNIQUE INDEX "idx__sqlite_migrations_migration_set_name"
ON "_sqlite_migrations" ("migration_set", "name");
CREATE TABLE "creatures" (
"id" INTEGER PRIMARY KEY,
"name" TEXT,
"species" INTEGER,
"weight" TEXT
);
_sqlite_migrations 表用于跟踪哪些迁移函数已运行。上面的 creatures 表是应用所有三个迁移后的模式。
要查看迁移列表,包括待处理和已应用的,请运行以下命令:
uvx sqlite-utils migrate data.db migrations.py --list
输出:
Migrations for: creatures
Applied:
create_table - 2026-07-07 17:58:41.360051+00:00
add_weight - 2026-07-07 17:58:41.360608+00:00
change_column_types - 2026-07-07 18:01:15.802000+00:00
Pending:
(none)
如果你没有指定迁移文件,sqlite-utils migrate data.db 命令将扫描当前目录及其子目录,查找名为 migrations.py 的文件,并应用在其中找到的任何 Migrations() 实例。
你也可以 从 Python 代码中 使用 migrations.apply(db) 方法执行迁移,这对于构建管理自己数据库模式的工具(支持多个版本)非常有用。我自己的 LLM 工具 已经使用这种模式多年,如 llm/embeddings_migrations.py 所示。
先前工作
我最喜欢的实现仍然是 Django 的迁移,由 Andrew Godwin 基于他早期的项目 South 开发。有趣的是:Andrew、Russ Keith-Magee 和我在2008年首届 DjangoCon 上的 Schema Evolution 小组讨论 中展示了各自处理 Django 模式迁移的方法!我的尝试叫做 dmigrations,由我在伦敦 Global Radio 的团队共同开发。
Django 的迁移可以从模型定义自动生成,并包括回滚到先前版本的能力。sqlite-utils 的方法有意更简单:与 Django 不同,sqlite-utils 鼓励程序化创建表,而不是使用模型定义 ORM,因此我们没有什么可以用来自动生成迁移。
我决定跳过回滚功能,因为根据我的经验,这是一个很少使用的功能。对于 SQLite 项目,实现回滚的一种简单方法是在应用迁移之前创建数据库文件的副本!
从 sqlite-migrate 迁移
sqlite-utils 迁移的设计已经有三年的历史了——我最初将其作为名为 sqlite-migrate 的独立包发布,但从未超过 beta 版本。
我在足够多的地方使用了这个包,以至于我对这个设计很有信心,因此我决定将其提升为 sqlite-utils 的一个功能,使其默认可用于不断增长的 sqlite-utils/Datasette/LLM 生态系统中的所有其他工具。
我发布了 最后一个版本的 sqlite-migrate,它改为依赖 sqlite-utils>=4,并将 __init__.py 文件替换为以下内容:
from sqlite_utils import Migrations __all__ = ["Migrations"]
任何依赖于 sqlite-migrate 的现有项目都应能继续工作,无需修改。
sqlite-utils 4.0 中的其他一切
以下是此版本的发布说明,附带一些内联注释:
4.0 版本包含一些轻微的不向后兼容的修复(因此主版本号升级),并引入了三个主要新功能: 数据库迁移,提供了一个结构化机制,用于随时间推移演变项目模式。(#752)
我认为迁移是标志性的新功能,因此写了这篇博客文章。
通过 db.atomic() 实现的嵌套事务支持,以及整个库中事务工作方式的诸多改进。(#755)
sqlite-utils 长期以来与数据库事务的关系一直很混乱,部分原因是我在 2018 年开始设计这个库时,对它们在 SQLite 本身中的工作方式还没有很好的感觉。
将迁移添加到核心库让我下定决心最终解决这个难题,因为事务使迁移系统更加安全和易于推理。
我最终围绕一个 db.atomic() 上下文管理器构建了它,看起来像这样:
with db.atomic():
db.table("dogs").insert({"id": 1, "name": "Cleo"}, pk="id")
db.table("dogs").insert({"id": 2, "name": "Pancakes"})
SQLite 支持 保存点,因此 db.atomic() 可以嵌套执行事务中的事务。这非常棒!
支持复合外键,包括通过 table.foreign_keys 创建、转换和内省。(#594)
这源于我让一个编码代理审查所有未解决的问题和 PR,找出应包含在 4.0 版本中的内容,因为如果以后添加它们将代表破坏性变更,它正确地识别出复合外键正是这类功能。
我从对 table.foreign_keys 内省方法做了一个破坏性变更开始,然后决定看看 Claude Fable 5 是否能处理将复合外键 创建 集成到库中的更繁琐工作。它帮助创建的 API 设计感觉 完全正确——与库的其他部分已经工作的方式一致。
其他值得注意的变化包括: Upserts 现在使用 SQLite 的 INSERT ... ON CONFLICT ... DO UPDATE SET 语法,自动检测现有表的主键,并拒绝缺少所需主键值的记录。(#652)
这是第一个促使我考虑进行破坏性变更 4.0 版本升级的变化。我构建这个是为了帮助支持 sqlite-chronicle,它使用触发器来跟踪表中已插入、更新或删除的行。
db.query() 现在立即执行,并拒绝不返回行的语句;对于写入和 DDL,请使用 db.execute()。
可能是 最具破坏性的破坏性变更——我不得不更新自己代码中的几个地方,将 db.query() 切换为 db.execute()。
CSV和TSV导入现在默认检测列类型,而插入到现有表时会保留这些表的列类型。(#679)
sqlite-utils insert data.db creatures creatures.csv --detect-types 标志是后来添加的,用于根据CSV中的数据自动检测列类型(text, integer, real)。它本应是默认行为,而发布4.0意味着我可以做到这一点。
table.extract() 和 extracts= 不再为全空值创建查找表记录。(#186)
此版本解决的最早问题——底层bug(由我)于2020年10月提交。
详见《从3.x升级到4.0》了解向后不兼容的变更。 4.0预发布周期中提供的功能和修复的详细发布说明可在4.0a0、4.0a1、4.0rc1、4.0rc2、4.0rc3和4.0rc4中找到。
升级指南完全由Claude Fable 5、Claude Opus 4.8和GPT-5.5撰写。发布说明也是如此。
这类文档是我逐渐放心外包给机器人的。它不需要说服任何人任何事情,也不需要表达任何观点——它的任务是尽可能准确和详细。我已经仔细审阅了发布说明,可以确认它们准确且全面。
Claude Fable 5帮了大忙
我在一年多前发布了sqlite-utils 4.0的第一个alpha版本。我一直在拖延稳定版发布,因为需要做大量工作来追踪和清理许多其他小的设计缺陷,而主要版本号允许我承担这些工作。
Claude Fable 5(以及较小程度上的Opus 4.8和GPT-5.5)的帮助给了我所需的推动力,让我克服惰性,充分利用我可以投入这个库的时间。
Fable在API设计上具有非常好的品味,而且如果你给它一个更开放的目标,它会不懈地主动。我最成功的提示词是一个审查任务,我针对我认为的最后一个候选版本发布了该任务:
审查自上次标记的3.x版本以来主分支上的变更——我即将将它们作为sqlite-utils 4.0发布,这是一个稳定版本,承诺在很长一段时间内不会有向后不兼容的修复。 审查变更日志和升级指南,并编写临时代码脚本以尝试v4中的所有新功能——保存这些脚本但不要提交它们
我在Codex Desktop中用GPT-5.5 xhigh尝试了这一点,并在Claude Code中使用了Fable 5。
GPT-5.5 编写了5个Python脚本,但没有发现什么特别有趣的东西——其最终报告在此。
Fable 5 编写了12个脚本,识别出4个发布阻塞问题和10个额外问题在其报告中,并构建了一个简洁的组合重现脚本,运行时输出以下内容:
=== 1. Failed db.execute() write leaves an implicit transaction open ===
in_transaction after failed write: True
BUG: table 'other' silently lost when connection closed
=== 2. Leading ';' bypasses the query() first-token scanner ===
BUG: raised OperationalError: no such savepoint: sqlite_utils_query
BUG: row persisted despite rollback (count=1)
=== 3. Rejected write PRAGMA via query() still takes effect ===
BUG: user_version=5 after 'rejected' statement (docs say no effect)
=== 4. Implicit compound FK resolves pk columns in table order, not PK order ===
BUG: other_columns reported as ('b', 'a'), should be ('a', 'b')
BUG: transform of valid data raised IntegrityError: FOREIGN KEY constraint failed
=== 5. ForeignKey (now a dataclass) is no longer hashable ===
BUG: cannot use 'sqlite_utils.db.ForeignKey' as a set element (unhashable type: 'ForeignKey')
=== 6. Mixed ForeignKey objects and tuples in foreign_keys= rejected ===
BUG: foreign_keys= should be a list of tuples
=== 7. insert --csv into an EXISTING table transforms its column types ===
BUG: existing zip '01234' is now 1234 (column type: int)
=== 8. insert(pk=, alter=True) regression: InvalidColumns before alter runs ===
BUG: InvalidColumns: Invalid primary key column ['id'] for table t with columns ['a']
=== 9. migrate --stop-before an already-applied migration applies everything ===
BUG: m2 was applied despite --stop-before m1 (m1 already applied)
=== 10. ensure_autocommit_on() silently commits an open transaction ===
BUG: row survived rollback (count=1) - transaction was committed
我发现自己同意几乎所有的建议。这是包含16个提交的PR,我们逐一解决了这些问题。
我毫不怀疑,sqlite-utils 4.0 的质量远高于我在没有最新前沿模型帮助的情况下所能构建的版本。
Tags: schema-migrations, projects, sqlite, ai, sqlite-utils, annotated-release-notes, generative-ai, llms, ai-assisted-programming, anthropic, claude, agentic-engineering, claude-mythos-fable
相关条目
89
精选OpenAI研究:AI正在重新定义工作边界
如果你关心AI对实际工作的影响,这篇研究不容错过。它不讨论理论,而是用数据展示ChatGPT用户如何使用AI扩展自己的任务范围,这对HR、管理者以及每个希望提升技能的职场人都有直接启发。
87
精选OpenAI CFO 分享构建 AI 原生财务职能的五大经验
作为编辑,我认为这篇文章的价值在于它来自 AI 领军企业的财务一把手,而非外部咨询机构,因此更具实践参考性。推荐给财务数字化负责人、CFO 以及对 AI 转型感兴趣的从业者阅读。
87
精选智能体AI时代下的科学计算:OpenAI发布新领域报告
这份报告是当前AI agent热潮中最务实的应用分析之一,尤其适合计算生物学和药物研发领域的从业者阅读。它回答了“AI agent除了写代码还能干什么”这个关键问题,直接展示了在复杂科学计算中的生产力提升。
87
精选Real World VoiceEQ:量化语音AI的人类自然度
值得关注的是,这个基准真正聚焦'人类自然度'这个软指标,而不是传统的语音识别率或MOS评分。对从事语音合成、语音克隆或语音交互的团队来说,这是一个非常实用的参考工具,可以快速定位模型在情感、韵律等层面上的不足。不过目前支持语言有限,期待后续扩展。
85
精选OpenAI 推出AI时代记分卡:衡量投资回报的新方法
这篇博文直击当前AI行业的软肋——如何量化投入产出。对于正在或计划大规模部署AI的企业决策者而言,它能帮助避免盲目跟风。我个人建议结合自身业务场景尝试定义“有用工作”,避免指标设计流于形式。
85
精选代理时代如何管理AI投资:聚焦每美元有用功与高价值工作流
这篇文章对正在大规模部署AI代理的企业尤为重要。它提醒我们:单纯盯着API价格下降会陷入误区,真正要管理的是每单位工作的投资回报率。建议CTO和CFO联合阅读,并在内部建立量化评估机制。
85
精选设计能跟上AI的组织:组织延迟成为最大障碍
这篇文章真正值得关注的是提出了一个被忽视的瓶颈:技术再强,组织跟不上也是白搭。对CTO、CIO和转型负责人来说,这是比技术选型更重要的思考框架。
84
精选Ruff v0.16.0 发布:默认规则从59条激增至413条,CI工作流需关注
对于 Python 开发者来说,这是一个不容错过的更新信号。Ruff 的默认规则大幅增加意味着我们不能再忽视代码中潜在的问题,而 AI 修复工具正好可以降低升级成本。尤其值得关注的是 Astral(OpenAI)正在将 AI 编码能力与静态分析工具深度整合,这可能是未来工程实践的常态。