SQLite 应该有(Rust 风格)版本
原文链接:https://mort.coffee/home/sqlite-editions/
SQLite 应该有(Rust 风格)版本 - Mort's Ramblings SQLite 应该有(Rust 风格)版本 Git:https://gitlab.com/mort96/blog/blob/published/content/00000-home/00017-sqlite-editions.md SQLite 是一个令人惊叹的数据库引擎。我用它作为大量嵌入式项目的数据库,我认为称其为行业标准并不夸张,一些服务器软件甚至使用它;例如,lobste.rs 现在在 SQLite 上运行。与传统的 RDBMS(关系数据库管理系统)不同,它是一个作为库的 RDBMS,这意味着您的软件保持独立。与传统的文件格式不同,您不需要编写在某些方面,它是两全其美的。但只有一个大问题。错误的默认值 #1:默认情况下会忽略外键约束 外键约束可以说是我们确保数据库保持一致且没有悬空引用的主要工具。作为快速入门,这是 SQL 外键约束的外观: FOREIGN KEY(user_id) REFERENCES users(id) 所有其他 RDBMS 的典型行为是帖子的 user_id 列必须始终引用有效用户的 ID。如果不提供有效的用户 ID,则无法创建新帖子;如果不删除用户的帖子,则无法删除用户,以免出现外键约束违规错误。据我所知,默认情况下唯一不强制执行此操作的 RDBMS 是 SQLite。
SQLite 重用 ROWID 的倾向使情况变得更糟。您会看到,在此示例中,那些 INTEGER PRIMARY KEY 行成为表 ROWID 的别名,ROWID 是分配给每一行的唯一整数 ID。分配 ROWID 的算法有点复杂(更多详细信息请参阅 SQLite 文档),但在某些情况下会导致 ID 重用。这意味着悬空引用很容易导致对错误列的引用,这比悬空引用更糟糕,因为您在查找过程中甚至不会收到错误。只需看看这个假设的操作序列 INSERT INTO users (display_name) VALUES ('Bob'); INSERT INTO posts (user_id, content) VALUES (1, '你好,我是鲍勃'); SELECT u.display_name, p.content FROM users as u, posts as p WHERE u.id = p.user_id; ——但我们忘记删除帖子了。
-- SQLite 不会产生错误,因为它忽略了我们的外键。
-- 由于 ROWID 算法,Alice 获得了与 Bob 相同的 ID。
INSERT INTO users (display_name) VALUES ('Alice'); -- Alice现在继承了Bob的旧职位!
SELECT u.display_name, p.content FROM users as u, posts as p WHERE u.id = p.user_id;修复方法是使用 pragma 启用foreign_keys:如果我们一开始就这样做了,有缺陷的 DELETE 会产生错误: -- 运行时错误:FOREIGN KEY 约束失败 (19) 错误的默认值 #2:列可以存储错误的数据类型 SQLite 有一个简单的类型系统:值可以是 NULL 、 INTEGER 、 REAL (又名双精度浮点数)、 TEXT 或 BLOB (又名二进制数据)。因此,可以定义列来保存任何这些类型的值。但是,定义为 INTEGER 列的列不仅限于整数;还可以是整数。相反,SQLite 认为它“使用 INTEGER 亲和力”。它是整数的有效字符串表示形式,它被转换为整数并按原样存储。它是实数的有效字符串表示形式,它被转换为实数(又名双精度浮点数)并按原样存储。否则,该值将按原样存储。其他关联性具有不同但更简单的规则:具有 BLOB 关联性的列按原样存储值。具有 TEXT 亲和性的列按原样存储 BLOB 、 TEXT 和 NULL 值,但将数值转换为 TEXT 。具有 REAL 亲和力的列的工作方式与具有 INTEGER 亲和力的列类似,只是整数值会转换为 REAL 。插入音乐(名称、d