SQLite 以其灵活宽松的类型系统著称——你可以在 INTEGER 列里塞进文本,也可以给 DATE 列赋个整数。这种”包容”在快速原型开发中很便利,但在生产环境中常常变成隐形炸弹。Evan Hahn 在一篇引发热议的博文中指出:SQLite 的 STRICT 表模式是这个问题的优雅解法,而你只需要在 CREATE TABLE 末尾加上一个单词。
一行改写,杜绝类型错乱
启用严格模式出奇简单:
CREATE TABLE people (name TEXT) STRICT;
仅此而已。一旦启用 STRICT,SQLite 将拒绝不符合列类型的插入和更新操作:
-- 普通表:允许任何类型
CREATE TABLE t1 (age INTEGER);
INSERT INTO t1 (age) VALUES ('garbage'); -- ✓ 通过
-- 严格表:拒绝类型不匹配
CREATE TABLE t2 (age INTEGER) STRICT;
INSERT INTO t2 (age) VALUES ('garbage'); -- ✗ 报错
STRICT 的三重保护
1. 阻止 INSERT/UPDATE 类型不匹配:最核心的保护。值得注意的是,SQLite 仍允许无损转换——字符串 ‘123’ 可以自动转为整数 123,这是合理的兼容设计。
2. 拒绝无效列类型:默认情况下你可以创建类型为 BOGUSTYPE 的列而不报错。STRICT 模式强制列类型必须为 SQLite 支持的严格类型(INT, INTEGER, REAL, TEXT, BLOB, ANY)。
3. 利于代码生成和 ORM 映射:有了 STRICT,工具可以更可靠地推断列类型,避免因”一切皆可为”导致的映射错误。
为什么不是默认行为?
答案很简单:向后兼容。SQLite 从 2000 年诞生以来一直采用灵活类型系统,突然改变默认行为会破坏无数现有应用。Hahn 的建议是:新项目一律用 STRICT,老项目逐步迁移。
社区反应
HN 评论区几乎一边倒地支持这个观点。”这真的应该是默认行为”、”我以为这已经是默认了”是最常见的两条评论。有用户分享了 ANY 类型的巧妙用法——用于审计表中按字段追踪变更。还有开发者建议将 STRICT 纳入 SQLite 的推荐实践文档。少数反对声音认为灵活类型在某些场景下(如数据导入清洗)有其价值,但大多认可 STRICT 作为默认选项的合理性。
一个单词的改动,带来的却是类型安全质的飞跃。如果你的项目使用 SQLite,今天就可以开始加 STRICT。
原文链接:Prefer strict tables in SQLite – Evan Hahn
HN 讨论:Hacker News (199 points, 89 comments)