0、参考资料
http://xstarcd.github.io/wiki/MySQL/MySQL-sql-mode.html
http://blog.csdn.net/wulantian/article/details/8905573
https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html
http://blog.csdn.net/wyzxg/article/details/8787878
https://blog.linuxeye.cn/379.html
1、技术场景
项目最近架构调整,老架构MySQL版本是5.6,新架构升级了一下MySQL版本,升级到了5.7。升级之后发现很多地方报错,都是MySQL相关的错误。
下面一个错误一个错误的分析。
错误一:
MySQL [pdmp]> select Fname,Fsource_name_code from t_data_source where Fenable = 'Y' and site = 'friso' group by Fsource_name_code;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'pdmp.t_data_source.Fname' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
从报错分析,是因为select的字段(非聚合函数),没有全部在group by中。那之前在老架构的MySQL的版本中能正常运行,新架构怎么就不行了?猜想应该是版本升级导致的。
去查看了一下老版本的sql_mode,结果如下:
SELECT @@GLOBAL.sql_mode;
+------------------------+
| @@GLOBAL.sql_mode |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
没有严格模式等相关限制。
再看看新版本的sql_mode,结果如下:
SELECT @@GLOBAL.sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------------------------------------------------------------------------------------+
问题就出在ONLY_FULL_GROUP_BY
上,去查了一下,如果添加上这个模式,
对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中。
错误二:
INSERT INTO `t_data_source`(`Fname`, `Fbrand`, `Fmarketing_type`, `Fdata_type`, `Fcreate_time`, `Factive`, `Fsource_name_code`, `site`) VALUES ('巴啦啦', 'ADF', '2', '1', '2018-03-12 09:46:07', '', '1', 'friso');
dispatch exception:SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column 'Factive' at row 1
从SQL报错上分析,可以很容易知道,是因为数据库字段类型和插入数据类型不匹配导致的。初步猜想和错误一的原因一致。后来发现是因为模式STRICT_TRANS_TABLES
导致的,在这种模式下:如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制。而我们刚好是开启事务的。
2、sql_mode介绍
介绍都是官网搬过来的。
ONLY_FULL_GROUP_BY:
对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中。
STRICT_TRANS_TABLES:
在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制。
NO_ZERO_IN_DATE:
在严格模式下,不允许日期和月份为零。
NO_ZERO_DATE:
设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
ERROR_FOR_DIVISION_BY_ZERO:
在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL。
NO_AUTO_CREATE_USER:
禁止GRANT创建密码为空的用户。
NO_ENGINE_SUBSTITUTION:
如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常。
PIPES_AS_CONCAT:
将"||"视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似。
ANSI_QUOTES:
启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符
3、修改sql_mode配置
查看sql_mode
select @@sql_mode;
show variables like 'sql_mode%'G;
sql_mode修改
set @@sql_mode=TRADITIONAL;
另外,可以直接修改my.ini文件,找到sql_mode,然后设置新的模式即可!
例如:
vi /etc/my.cnf
在[mysqld]下面添加如下列:
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES