在部落格系統中,blogs (文章) 與 comments (留言) 存在一對多關係。若僅在應用層維護完整性:
blog_id,併發下極易不一致。資料庫原生外鍵約束將完整性維護下沉至儲存引擎層,實現 聲明式完整性:定義規則一次,自動終身生效。
CREATE TABLE `blogs` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`title` TEXT,
`content` TEXT,
`author` VARCHAR(45)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `comments` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`blog_id` INT UNSIGNED NOT NULL,
`comment` TEXT,
`author` VARCHAR(45),
INDEX `idx_blog_id` (`blog_id`),
CONSTRAINT `fk_comments_blogs`
FOREIGN KEY (`blog_id`) REFERENCES `blogs` (`id`)
ON UPDATE CASCADE
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
| 子句 | 觸發時機 | 行為 | 適用場景 |
|---|---|---|---|
ON UPDATE CASCADE | 父表主鍵值變更 | 自動更新所有子表外鍵值 | 主鍵為自然鍵、業務需變更 ID |
ON DELETE CASCADE | 父表記錄刪除 | 自動刪除所有關聯子記錄 | 強依賴關係:文章刪除 → 留言同步刪除 |
ON UPDATE SET NULL | 父表主鍵值變更 | 子表外鍵設為 NULL | 弱依賴:分類變更 → 產品分類置空 |
ON DELETE SET NULL | 父表記錄刪除 | 子表外鍵設為 NULL | 保留子記錄但切斷關聯 |
ON UPDATE RESTRICT / NO ACTION | 父表主鍵值變更 | 阻止更新,拋出錯誤 | 嚴格禁止父鍵變更 |
ON DELETE RESTRICT / NO ACTION | 父表記錄刪除 | 阻止刪除,拋出錯誤 | 預設行為,保護歷史數據 |
-- 僅需執行單條語句
UPDATE blogs SET id = 2 WHERE id = 1;
-- InnoDB 自動執行:
-- UPDATE comments SET blog_id = 2 WHERE blog_id = 1;
無需應用層干預,ACID 保證原子性:父表更新失敗則全回滾,子表更新失敗亦回滾父表。
ERROR 1822。SET foreign_key_checks = 0; 可暫時禁用檢查 (匯入數據時),操作完成後**務必重新啟用**。MyISAM 僅語法解析 FOREIGN KEY 但**不執行任何約束檢查**,僅為相容性保留。生產環境**嚴禁**依賴 MyISAM 外鍵。
ALTER TABLE ... ADD CONSTRAINT ...。| 誤區 | 真相 |
|---|---|
| 外鍵會大幅降低寫入效能 | 單行操作開銷微乎其微;大批量操作可暫時禁用檢查。讀取效能無影響。 |
| 所有關聯都要加外鍵 | 僅對**強一致性要求**的核心業務表添加;日誌、統計、緩存表不需要。 |
| 外鍵解決了所有完整性問題 | 無法約束跨資料庫、跨實例、應用層邏輯刪除 (如軟刪除) 等場景。 |
| CASCADE 刪除會觸發 Trigger | MySQL 中外鍵級聯操作**不會**觸發子表的 BEFORE/AFTER DELETE Trigger。 |
外鍵約束是關係型資料庫區別於 NoSQL 的核心特性之一。善用 InnoDB 原生外鍵,能以最小代價換取最大資料可靠性,是架構演進的關鍵里程碑。