sqlite-utils 4.0rc1 新增迁移与嵌套事务
sqlite-utils 4.0rc1 adds migrations and nested transactions
sqlite-utils 4.0rc1 发布,这是其 v4 的首个候选版本,由开发者 Simon Willison 维护。该版本引入两个新特性:数据库迁移(migrations)功能,支持通过 Python 或 CLI 命令 `sqlite-utils migrate` 执行迁移;以及 `db.atomic()` 事务,基于 SQLite savepoints 实现嵌套事务。向后不兼容变更包括:Upsert 改用 `INSERT ... ON CONFLICT SET` 语法;放弃 Python 3.8 支持,新增 Python 3.13 支持;`db.table()` 仅适用于表,视图需用 `db.view()`;默认浮点列类型从 `FLOAT` 改为 `REAL`;表模式使用双引号包裹名称;CSV/TSV 导入默认启用类型检测。
sqlite-utils 是我开发的用于操作 SQLite 数据库的 Python 库和 CLI 工具组合。它在 Python 默认的 sqlite3 包之上提供了大量高级操作,包括支持复杂的表转换、从 JSON 数据自动创建表等等。我发布了 sqlite-utils 4.0rc1,这是 sqlite-utils v4 的第一个候选发布版本。主版本号的提升意味着一些(轻微的)向后不兼容变更,因此我希望在正式发布稳定版之前,让大家先试用一下。
新特性:迁移(migrations)
与之前的 4.0 alpha 版本相比,这个 RC 版本有两个重要的新特性。第一个是支持数据库迁移。这并不是一个全新的实现——它是对我几年前发布的 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 主要通过 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"})
更多细节请参阅文档。
向后不兼容的变更
v4 中的向后不兼容变更已在 alpha 发布说明中描述。
对于 4.0a0:
- Upsert 操作现在在所有高于 3.23.1 的 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)
--functionsCLI 参数现在除了接受包含 Python 代码的字符串外,还接受 Python 文件的路径。它现在也可以多次指定。(#659)- 破坏性变更:在导入 CSV 或 TSV 数据时,类型检测现在是
insert和upsertCLI 命令的默认行为。之前所有列都被视为TEXT,除非传递了--detect-types标志。使用新的--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。
标签:migrations, projects, sqlite, sqlite-utils, annotated-release-notes