應用層維護關聯完整性(如:刪除部落格文章時同步刪除留言)程式碼複雜、易出錯、效能差。資料庫層級的外鍵約束(FOREIGN KEY)能自動執行級聯動作,確保資料一致性,簡化應用邏輯。
| 動作 | 觸發條件 | 子表行為 | 適用場景 |
|---|---|---|---|
CASCADE | 父表 UPDATE/DELETE | 同步 UPDATE/DELETE 關聯行 | 訂單-明細、文章-留言、部門-員工 |
SET NULL | 父表 UPDATE/DELETE | 外鍵欄位設為 NULL(需允許 NULL) | 可選關聯、軟刪除保留子記錄 |
NO ACTION | 父表 UPDATE/DELETE | 拒絕操作,報錯(標準 SQL 行為) | 嚴格保護父記錄 |
RESTRICT | 父表 UPDATE/DELETE | 拒絕操作,報錯(MySQL 預設) | 同 NO ACTION,檢查時機更早 |
SET DEFAULT | 父表 UPDATE/DELETE | 外鍵欄位設為 DEFAULT 值 | 極少用,需有 DEFAULT 值 |
CREATE TABLE `blogs` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` TEXT NOT NULL,
`content` TEXT NOT NULL,
`author` VARCHAR(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `comments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`blog_id` INT UNSIGNED NOT NULL,
`comment` TEXT NOT NULL,
`author` VARCHAR(45) DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_blog_id` (`blog_id`),
CONSTRAINT `fk_comments_blog`
FOREIGN KEY (`blog_id`) REFERENCES `blogs` (`id`)
ON UPDATE CASCADE
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INDEX idx_blog_id:外鍵欄位必須有索引,InnoDB 會自動建立若未指定CONSTRAINT fk_comments_blog:命名約束,便於管理與除錯ON UPDATE CASCADE:父表 id 變更時,子表 blog_id 自動同步ON DELETE CASCADE:刪除文章時,關聯留言自動刪除-- 插入測試資料
INSERT INTO blogs (title, content, author) VALUES ('第一篇', '內容...', 'Ian');
INSERT INTO comments (blog_id, comment, author) VALUES (1, '留言1', 'Susan'), (1, '留言2', 'Rose');
-- 更新父表主鍵(觸發 ON UPDATE CASCADE)
UPDATE blogs SET id = 2 WHERE id = 1;
-- 檢查子表
SELECT * FROM comments; -- blog_id 已自動變為 2
-- 刪除父表記錄(觸發 ON DELETE CASCADE)
DELETE FROM blogs WHERE id = 2;
-- 檢查子表
SELECT * FROM comments; -- 關聯留言已自動刪除
A → B → C 三層關聯,若 A 刪除級聯到 B,B 刪除再級聯到 C。需注意:
SET FOREIGN_KEY_CHECKS=0; 操作完 SET FOREIGN_KEY_CHECKS=1;pt-online-schema-change 或維護窗口EXPLAIN 確認 ref 類型-- 1. 轉換引擎
ALTER TABLE blogs ENGINE=InnoDB;
ALTER TABLE comments ENGINE=InnoDB;
-- 2. 確保欄位型別完全一致(含 UNSIGNED、長度)
-- 3. 清理髒資料(孤兒記錄)
DELETE c FROM comments c LEFT JOIN blogs b ON c.blog_id = b.id WHERE b.id IS NULL;
-- 4. 加外鍵
ALTER TABLE comments
ADD CONSTRAINT fk_comments_blog
FOREIGN KEY (blog_id) REFERENCES blogs(id)
ON UPDATE CASCADE ON DELETE CASCADE;
| 錯誤 | 原因 | 解決 |
|---|---|---|
| Cannot add foreign key constraint | 欄位型別不符、父表無主鍵/唯一索引、資料不一致 | 對齊型別、建索引、清理髒資料 |
| Foreign key constraint fails | 插入子表時父表無對應值、刪除父表時子表有關聯且非 CASCADE | 先插父表、或改 CASCADE |
| Deadlock found | 並發更新父子表順序不一致 | 應用層固定加鎖順序(先父後子) |
外鍵約束是關聯式資料庫維護資料完整性的核心機制。InnoDB 完整支援 CASCADE/SET NULL/RESTRICT 等動作,能大幅簡化應用邏輯。權衡寫入效能與資料安全,核心業務表強烈建議使用 InnoDB + 明確外鍵約束,並配合合理的索引與監控。