
怎么查当前 SQL 模式?别猜,直接看
你改没改成功、程序连的是哪个模式,全靠 SELECT @@sql_mode 或 SELECT @@global.sql_mode 说话。前者查当前连接(会话级),后者查全局默认值——但注意:@@global.sql_mode 只影响新建立的连接,已存在的连接不会变。
-
SELECT @@SESSION.sql_mode和SELECT @@sql_mode效果一样,推荐用后者,更简洁 - 返回结果是一长串逗号分隔的模式名,比如
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_DATE,顺序无关,MySQL 自己解析 - 如果返回空字符串,说明当前是“宽松模式”,很多非法插入只会警告不报错,容易埋坑
临时改模式:会话级 vs 全局级,别混用
临时改就是不写配置文件、不重启 MySQL 的快速调试方式,但得清楚作用域——不然你会纳闷“我明明 SET 了,为什么 Java 程序还是报错?”
- 会话级:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE',只对当前这个命令行 / 连接生效,关掉终端就失效 - 全局级:
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE',新连上来的客户端(比如 Spring Boot 重启后的新连接)才会用这个模式;已有连接完全不受影响 - 常见误操作:在 MySQL 客户端里 SET GLOBAL,然后立刻执行 INSERT 测试——结果还是老模式,因为你的当前会话没刷新,得
EXIT再重连才生效
永久生效:改配置文件必须重启,且路径和语法有坑
生产环境要稳定,必须走配置文件。但 MySQL 8.0+ 和旧版本写法不同,Linux 和 Windows 路径也不同,配错会导致 MySQL 启动失败。
- 配置项名是
sql_mode(不是sql-mode,后者在 MySQL 8.0+ 已废弃,用了会启动失败) - Linux 常见路径:
/etc/my.cnf或/etc/mysql/my.cnf;Windows 是C:\ProgramData\MySQL\MySQL Server x.x\my.ini - 必须加在
[mysqld]段落里,例如:[mysqld]<br>sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
- 双引号可选,但建议加上,避免空格或特殊字符引发解析问题;值里不能有多余换行或注释
- 改完必须
sudo systemctl restart mysql(Linux)或服务管理器重启,光 reload 不行
Strict 模式组合怎么选?别无脑抄 TRADITIONAL
TRADITIONAL 看起来省事,但它等价于 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,其中 NO_AUTO_CREATE_USER 在 MySQL 8.0+ 已彻底移除——你配了它,MySQL 就起不来。
- 推荐最小可用严格组合:
STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION -
ONLY_FULL_GROUP_BY很有用,但会卡住某些旧业务的 GROUP BY 写法(比如SELECT a, MAX(b) FROM t GROUP BY a却选了c字段),上线前务必全量回归测试 - 开发环境可先开
STRICT_TRANS_TABLES单独试水,它只对事务表严格,风险可控;线上再逐步加其他项
最常被忽略的一点:ORM 框架(比如 MyBatis、Hibernate)可能在连接 URL 里硬编码了 sessionVariables=sql_mode=xxx,这时候配置文件和 SET GLOBAL 都会被覆盖——得去检查连接串和初始化 SQL。










