sql_mode是个很容易被忽视的变量,默认值是空值,在这种设置下是可以允许一些非法操作的,比如允许一些非法数据的插入。
一些现象
之前开发的时候,发现一些奇怪的情况:
我一个字段设置为NOT NULL,而且不给其设置默认值,就算执行的插入sql中没有这个字段,mysql也会给字段填充上对应类型的默认值(int=>0,varchar=>空字符串)。
还有就是比如一个字段是varchar(20),然后我插入一个长度为200的字符串也同样不会报错,数据库会自动截取字符串来入库。
类似的情况还有,不过我发现mysql都不会报错,还会自动帮助转换。
新问题
今天朋友说,他一个字段设置为NOT NULL,且没给默认值,插入的时候报错了。1364:xx字段没有默认值。
奇怪的是,同样代码,且mysql数据库版本一致的本地缺没有报错,只有线上报错了。
百度找到答案后,我发现,之前我遇到这个问题,一直还以为是mysql的版本问题,今天才知道,不是的。。。
是因为线上和本地的mysql变量sql_mode的设置不同,他线上设置了很多值,校验相当的严格了。(严格模式),而我之前所有的设置都是直接为空,或者就是简单的 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION (宽松模式)
sql_mode常用值
可以使用sql语句 show variables like 'sql_mode'; 来查看你当前 sql_mode 的设置。
修改设置的话,在mysql配置文件(my.ini 或 my.cnf)中的 [mysqld] 模块下。
以下列举了几个常用值,和简单解释:
1. ONLY_FULL_GROUP_BY
对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中
如果不想改数据库配置,可以试着在select取的字段加函数绕过验证,比如 MAX(name), ABS,SUM之类的
2. NO_AUTO_VALUE_ON_ZERO
该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户 希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。
3. STRICT_TRANS_TABLES
在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制
4. NO_ZERO_IN_DATE
在严格模式下,不允许日期和月份为零
5. ERROR_FOR_DIVISION_BY_ZERO
在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL
6. NO_AUTO_CREATE_USER:
禁止GRANT创建密码为空的用户
7. NO_ENGINE_SUBSTITUTION
如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常
8. ANSI_QUOTES
启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符
最后
具体怎么设置看个人,我自己是比较喜欢宽松模式的,具体字段值的校验放在代码层来做,在入库前做检查。
我的设置:
[mysqld]
sql_mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"