萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL TRUNCATE 外鍵約束報錯 1701 秒解:關閉檢查→清空→重開檢查

錯誤現場

ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint
(`laravel-test`.`bl_role_user`, CONSTRAINT `role_user_role_id_foreign`
FOREIGN KEY (`role_id`) REFERENCES `laravel-test`.`bl_roles` (`id`))

原因:TRUNCATE TABLE 會隱式提交並嘗試快速刪除整表,但 InnoDB 偵測到有**子表透過外鍵引用此表**,為維護參考完整性直接拒絕。

標準三步驟解法(Session 級,不影響其他連線)

SET FOREIGN_KEY_CHECKS = 0;   -- 1. 關閉外鍵檢查
TRUNCATE TABLE bl_roles;      -- 2. 執行清空
SET FOREIGN_KEY_CHECKS = 1;   -- 3. 立即恢復檢查

為什麼用 Session 級而非 Global?

  • SET FOREIGN_KEY_CHECKS = 0 預設為 **SESSION 級**,僅影響當前連線。
  • 其他業務連線繼續受外鍵保護,**零風險污染**。
  • 若誤用 SET GLOBAL FOREIGN_KEY_CHECKS = 0,全庫外鍵失效,極度危險。

替代方案對比

Laravel / Eloquent 專用技巧

// 遷移檔中
Schema::table('bl_role_user', function (Blueprint $table) {
    $table->dropForeign(['role_id']);   // 先刪 FK
});
// 再 TRUNCATE bl_roles
// 最後加回 FK

// 或在 Seeder 中
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
DB::table('bl_roles')->truncate();
DB::statement('SET FOREIGN_KEY_CHECKS=1;');

驗證清空後狀態

SELECT COUNT(*) FROM bl_roles;           -- 0
SHOW TABLE STATUS LIKE 'bl_roles'\G
-- Auto_increment: 1  (已重置)

⚠️ 生產環境紅線

  • **嚴禁**在業務高峰期對核心表執行此操作。
  • 操作前**必須備份**(mysqldump --single-transaction)。
  • 確認無其他服務正在寫入相關表(可短暫停用寫入入口)。
  • 操作後立即驗證 FOREIGN_KEY_CHECKS=1 已生效:SHOW VARIABLES LIKE 'foreign_key_checks';
copyright © 萬盛學電腦網 all rights reserved
方案優點缺點適用場景
SET FK=0; TRUNCATE; SET FK=1;極快、不產生 Binlog 大量行刪除、重置自增 ID需確保無孤兒資料、暫時失去 FK 保護開發/測試/重建環境、大表清空重載
DELETE FROM table;觸發 FK CASCADE/RESTRICT、產生 Binlog、可回滾慢、產生大量 Undo/Redo、不重置自增 ID生產少量刪除、需審計追蹤
刪除 FK → TRUNCATE → 重建 FK徹底乾淨需鎖表、DDL 耗時、鎖定元資料結構變更窗口