SQL Mode 定義 MySQL 支援的 SQL 標準兼容度、數據驗證嚴格程度、錯誤處理行為。可在啟動參數、配置檔、會話級動態調整。本文系統梳理核心模式、嚴格模式邏輯、常見組合與生產環境推薦配置。
-- 啟動參數
mysqld --sql-mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
-- 配置檔 my.cnf
[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
-- 會話級動態修改
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,ANSI_QUOTES';
SET GLOBAL sql_mode = '...'; -- 需 SUPER 權限,影響後續新連線
-- 查看當前
SELECT @@sql_mode; -- 或 SHOW VARIABLES LIKE 'sql_mode';
| 模式 | 分類 | 核心影響 |
|---|---|---|
| STRICT_TRANS_TABLES | 嚴格模式 | 事務表:非法值報錯回滾;非事務表:首行非法報錯,後續行截斷/調整並警告 |
| STRICT_ALL_TABLES | 嚴格模式 | 所有表統一:非法值直接報錯回滾(可能導致部分寫入) |
| TRADITIONAL | 組合模式 | STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION ——「傳統」資料庫行為:錯誤即停止 |
| ANSI | 標準兼容 | 啟用 ANSI_QUOTES、PIPES_AS_CONCAT、REAL_AS_FLOAT 等,行為更接近標準 SQL |
| NO_ENGINE_SUBSTITUTION | 引擎保護 | 指定引擎不可用時**報錯**而非靜默回退預設引擎,防止生產意外 |
| NO_AUTO_CREATE_USER | 安全 | 禁止 GRANT 隱式建用戶(需顯式 IDENTIFIED BY),5.7+ 預設開啟 |
| NO_ZERO_DATE / NO_ZERO_IN_DATE | 日期驗證 | 嚴格模式下拒絕 0000-00-00、月/日為 0 的日期;非嚴格模式僅警告 |
| ERROR_FOR_DIVISION_BY_ZERO | 數學驗證 | 嚴格模式下除零報錯;非嚴格返回 NULL + 警告 |
| ONLY_FULL_GROUP_BY | 聚合規範 | 禁止 SELECT 列表含非聚合且不在 GROUP BY 的列(5.7+ 預設開啟) |
| ANSI_QUOTES | 識別符 | " 視為識別符引號,不可用於字串常量 |
| IGNORE_SPACE | 函數解析 | 允許函數名與 ( 間有空格,導致函數名成為保留字 |
| HIGH_NOT_PRECEDENCE | 運算符優先級 | NOT a BETWEEN b AND c 解析為 NOT (a BETWEEN b AND c)(標準行為) |
| NO_BACKSLASH_ESCAPES | 轉義 | 禁用 \ 作為字串轉義字符 |
| NO_AUTO_VALUE_ON_ZERO | AUTO_INCREMENT | INSERT 0 不生成自增值,僅 NULL 觸發;配合 mysqldump 還原防止自增值偏移 |
| PAD_CHAR_TO_FULL_LENGTH | CHAR 類型 | CHAR(n) 檢索時保留尾部空格(預設修剪) |
STRICT_TRANS_TABLES 或 STRICT_ALL_TABLES → 非法/缺失值 → **報錯、整個語句回滾**。STRICT_TRANS_TABLES:首行非法 → 報錯停止;後續行非法 → **截斷/調整為最接近合法值 + 警告**,語句繼續執行。STRICT_ALL_TABLES:任何行非法 → **報錯停止**,前面已寫入的行**不回滾**(非事務表無回滾能力),造成部分寫入風險。NO_ZERO_DATE + NO_ZERO_IN_DATE → 完全拒絕零日期/零月日。INSERT IGNORE 或 UPDATE IGNORE 降級為警告。# MySQL 5.7/8.0 現代嚴格兼容模式(官方預設)
STRICT_TRANS_TABLES,
NO_ENGINE_SUBSTITUTION,
NO_ZERO_DATE,
NO_ZERO_IN_DATE,
ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,
ONLY_FULL_GROUP_BY
# 等同於 5.7+ 預設:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
TRADITIONAL:含 STRICT_ALL_TABLES,非事務表部分寫入風險大。ONLY_FULL_GROUP_BY、NO_ZERO_DATE 過渡,逐步修正應用 SQL。| 現象 | 原因 | 對策 |
|---|---|---|
ERROR 1067: Invalid default value for 'col' | NO_ZERO_DATE 禁止 0000-00-00 默認值 | 改默認值為 NULL 或合法日期,或暫時移除 NO_ZERO_DATE |
ERROR 1365: Division by 0 | ERROR_FOR_DIVISION_BY_ZERO + 嚴格模式 | 業務邏輯加 IF(divisor=0, NULL, a/divisor) 或用 NULLIF |
ERROR 1055: 'db.t.col' isn't in GROUP BY | ONLY_FULL_GROUP_BY | 補全 GROUP BY 列、或用 ANY_VALUE(col)、或暫時關閉該模式 |
建表指定 ENGINE=Tokudb 卻悄悄變 InnoDB | 缺 NO_ENGINE_SUBSTITUTION,引擎缺失靜默回退 | 開啟 NO_ENGINE_SUBSTITUTION,缺失時直接報錯 |
NO_ENGINE_SUBSTITUTION。STRICT_TRANS_TABLES、NO_ZERO_DATE、NO_ZERO_IN_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、ONLY_FULL_GROUP_BY。NO_AUTO_CREATE_USER(內建強制)、PAD_CHAR_TO_FULL_LENGTH;NO_AUTO_VALUE_ON_ZERO 廢棄。精準掌控 SQL Mode,讓 MySQL 在數據完整性、標準兼容、遷移平滑三者間取得最佳平衡。