D1 支持在数据库的表之间定义和强制执行外键约束。
外键约束允许您强制执行表之间的关系。例如,您可以使用外键在 users 表的 user_id 和 orders 表的 user_id 之间创建严格绑定,这样就不能为不存在的用户创建订单。
外键约束还可以防止您删除被其他表中的行引用的行。例如,当 orders 表中的行引用 users 表中的行时,删除 users 表中的行。
默认情况下,D1 强制执行外键约束在所有查询和迁移中有效。这与在每个事务中设置 PRAGMA foreign_keys = on 的 SQLite 行为相同。
在对 D1 数据库运行查询、迁移或导入数据时,可能需要在创建表或更改 schema 期间临时禁用外键验证。
D1 的外键强制执行等同于 SQLite 的 PRAGMA foreign_keys = on 指令。由于 D1 在隐式事务中运行每个查询,用户查询无法在查询或迁移期间更改此设置。
相反,D1 允许您调用 PRAGMA defer_foreign_keys = on 或 off,这允许您临时违反外键约束(直到当前事务结束)。
调用 PRAGMA defer_foreign_keys = off 不会禁用当前事务之外的外键强制执行。如果您在事务结束时未解决未完成的外键违规,将失败并返回 FOREIGN KEY constraint failed 错误。
要延迟外键强制执行,在事务开始时或在会进行违规更改之前设置 PRAGMA defer_foreign_keys = on:
-- Defer foreign key enforcement in this transaction.
PRAGMA defer_foreign_keys = on
-- Run your CREATE TABLE or ALTER TABLE / COLUMN statements
ALTER TABLE users ...
-- This is implicit if not set by the end of the transaction.
PRAGMA defer_foreign_keys = off您也可以在解决未完成的外键约束后立即显式设置 PRAGMA defer_foreign_keys = off。如果仍有未完成的外键约束,您将收到 FOREIGN KEY constraint failed 错误,需要解决违规。
外键关系可以在通过 CREATE TABLE 创建表时定义,或在通过 ALTER TABLE 语句向现有表添加列时定义。
以基于电子商务网站的两表示例说明:
- 一个
users表,定义用户账户的常见属性,包括唯一的user_id标识符。 - 一个
orders表,将订单映射回用户表中的user_id。
此映射定义为 FOREIGN KEY,确保:
- 您不能从
users表删除会违反外键约束的行。这意味着您不会最终出现没有有效用户可映射的订单。 orders始终针对有效的user_id定义,降低创建引用无效(或不存在)用户的订单的风险。
CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
email_address TEXT,
name TEXT,
metadata TEXT
)
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
status INTEGER,
item_desc TEXT,
shipped_date INTEGER,
user_who_ordered INTEGER,
FOREIGN KEY(user_who_ordered) REFERENCES users(user_id)
)每个表可以定义多个外键关系,外键定义可以引用整个数据库 schema 中的多个表。
您可以在外键定义中定义操作,以限制或传播对父行(REFERENCES table(column))的更改。定义操作使在应用中使用外键约束更容易理解和推理,并帮助清理相关数据或防止数据孤立。
定义 ON UPDATE 和/或 ON DELETE 子句作为外键关系的一部分时,可以设置五种操作。根据需求,可以为 ON UPDATE 和 ON DELETE 定义不同的操作。
CASCADE- 更新或删除父键时,删除所有关联的子键(行)。RESTRICT- 当任何子键引用父键时,不能更新或删除父键。与默认外键强制执行不同,应用了RESTRICT的关系立即返回错误,而不是在事务结束时。SET DEFAULT- 将外键定义引用的子列设置为 schema 中定义的DEFAULT值。如果子列未设置DEFAULT,则不能使用此操作。SET NULL- 将外键定义引用的子列设置为 SQLNULL。NO ACTION- 不采取任何操作。
在以下示例中,从 users 表删除用户将删除 scores 表中的所有相关行,因为您定义了 ON DELETE CASCADE。如果您不想完全保留已删除用户的分数,请删除 scores 表中的所有相关行。这可能意味着其他用户无法再查找或引用仍然有效的分数。
CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
email_address TEXT,
)
CREATE TABLE scores (
score_id INTEGER PRIMARY KEY,
game TEXT,
score INTEGER,
player_id INTEGER,
FOREIGN KEY(player_id) REFERENCES users(user_id) ON DELETE CASCADE
)- 阅读 SQLite
FOREIGN KEY↗ 文档。 - 了解如何在 Worker 中使用 D1 Workers Binding API。
- 了解数据库迁移在 D1 中的工作原理。