首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL SQL Mode 詳解:ANSI、STRICT、TRADITIONAL、NO_ENGINE_SUBSTITUTION 等模式對行為的影響

     編輯:MySQL 綜合教學

MySQL SQL Mode 詳解:ANSI、STRICT、TRADITIONAL、NO_ENGINE_SUBSTITUTION 等模式對行為的影響

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_ZEROAUTO_INCREMENTINSERT 0 不生成自增值,僅 NULL 觸發;配合 mysqldump 還原防止自增值偏移
PAD_CHAR_TO_FULL_LENGTHCHAR 類型CHAR(n) 檢索時保留尾部空格(預設修剪)

三、嚴格模式深度邏輯

3.1 事務表

  • 啟用 STRICT_TRANS_TABLES 或 STRICT_ALL_TABLES → 非法/缺失值 → **報錯、整個語句回滾**。

3.2 非事務表

  • STRICT_TRANS_TABLES:首行非法 → 報錯停止;後續行非法 → **截斷/調整為最接近合法值 + 警告**,語句繼續執行。
  • STRICT_ALL_TABLES:任何行非法 → **報錯停止**,前面已寫入的行**不回滾**(非事務表無回滾能力),造成部分寫入風險。

3.3 日期零值處理

  • 嚴格模式 + 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 0ERROR_FOR_DIVISION_BY_ZERO + 嚴格模式業務邏輯加 IF(divisor=0, NULL, a/divisor) 或用 NULLIF
ERROR 1055: 'db.t.col' isn't in GROUP BYONLY_FULL_GROUP_BY補全 GROUP BY 列、或用 ANY_VALUE(col)、或暫時關閉該模式
建表指定 ENGINE=Tokudb 卻悄悄變 InnoDB缺 NO_ENGINE_SUBSTITUTION,引擎缺失靜默回退開啟 NO_ENGINE_SUBSTITUTION,缺失時直接報錯

六、版本演進提示

  • 5.6:預設 NO_ENGINE_SUBSTITUTION。
  • 5.7:預設加入 STRICT_TRANS_TABLES、NO_ZERO_DATE、NO_ZERO_IN_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、ONLY_FULL_GROUP_BY。
  • 8.0:移除 NO_AUTO_CREATE_USER(內建強制)、PAD_CHAR_TO_FULL_LENGTH;NO_AUTO_VALUE_ON_ZERO 廢棄。

精準掌控 SQL Mode,讓 MySQL 在數據完整性、標準兼容、遷移平滑三者間取得最佳平衡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved