开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
MySQL有很多知识点很小,也不起眼,但是往往在工作当中会导致各种各样的问题,其中sql-mode就是其中之一,在不关注的前提下很容易在插入关联数据的时候发生错误,那么今天就全方位的聊聊sql-mode吧。
sql-mode是一组mysql的语法校验规则,定义了mysql应该支持的sql语法、数据校验等规则,不同的MySQL版本默认值也不同,以5.7版本为例,为啥要强调MySQL版本呢?因为MySQL5.6的mode是NO_ENGIN_SUBSTITUTION,表示一个空值,相当于没有模式设置,可以理解为宽松模式。5.7的mode是STRICT_TRANS_TABLES,也就是严格模式。我们通过下面几个方面来认识他。
查看sql-mode
这里要了解的第一个事情就sql-mode的层级,也可以理解为他的作用域,从小到大来说:
会话级别(session):
只对当前操作生效,重启服务器之后就会失效。
这里的会话(Session) 可以理解成通信双方从开始通信到通信结束期间的一个上下文(Context),他和连接还是有区别的,之后我们专门来聊聊。
mysql> select @@session.sql_mode\G;
*************************** 1. row ***************************
@@session.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
1 row in set (0.00 sec)
ERROR:
No query specified
全局级别(global):
对下次连接开始的操作生效,但是MySQL重启之后会失效。
这里要搞明白一个问题,就是一个连接可以有0到多个会话
mysql> select @@global.sql_mode\G;
*************************** 1. row ***************************
@@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
1 row in set (0.00 sec)
ERROR:
No query specified
配置级别
上述的两种修改都可能在mysql重启之后失效,如果想更加持久生效的化,只能通过配置mysql的配置文件:
| 系统类型 | 默认配置文件位置 |
|---|---|
| linux(centos) | /etc/my.conf |
| windows | 安装目录下 my.ini |
查看配置当中的sql_mode配置就可以了
sql-mode常用值
ONLY_FULL_GROUP_BY
设置了这个值,如果使用GROUP BY,在SELECT后面出现的字段,在GROUP BY后面必须出现,不然报错如下:
mysql> select * from goods group by origin_place;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'practice.goods.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
STRICT_TRANS_TABLES
严格模式控制MySQL如何处理数据更改语句中的无效或缺失值,如INSERT或UPDATE。一个值可能因多种原因无效。例如,它可能具有列的错误数据类型,或者它可能超出了范围。如果要插入的新行不包含定义中没有显式DEFAULT子句的非null列的值,则该值缺失。
比如我们的某个字段设置不能为NULL,而我们插入的数据这个字段为NULL,那么就不能通过,就会报错如下:
create table goods_type(id int primary key auto_increment, t_name varchar(32) not null);
mysql> insert into goods_type(t_name) values(null);
ERROR 1048 (23000): Column 't_name' cannot be null
mysql> insert into goods_type(id) values(2);
ERROR 1364 (HY000): Field 't_name' doesn't have a default value
NO_ZERO_IN_DATE
NO_ZERO_IN_DATE模式会影响服务器是否允许年部分不为零但月或日部分为0的日期。 使用这个模式,可以插入 0000-00-00
NO_ZERO_DATE
设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
上面的NO_ZERO_IN_DATE可以插入'0000-00-00',如果使用了严格模式STRICT_TRANS_TABLES和NO_ZERO_DATE,那么就不可以插入'0000-00-00'。
ERROR_FOR_DIVISION_BY_ZERO
基于数学严谨性的一个校验模式,对于INSERT或者UPDATE中,如果被除数为0,那么就会产生错误,数据无法插入,MOD(N,M)也是一样,如果不设置mysql会插入或修改为null
NO_AUTO_CREATE_USER
不能使用grant命令创建密码为空的用户。
NO_ENGINE_SUBSTITUTION
如果指定了NO_ENGINE_SUBSTITUTION,我们在创建表或者修改表的时候,如果去指定了不存在或者不支持的存储引擎,那么就会报错,无法创建和修改,如果没有配置NO_ENGINE_SUBSTITUTION,那么就会将我们指定的存储引擎(不支持或者不存在)的存储引擎替换为默认的存储引擎,MySQL5.7后的默认存储引擎为InnoDB,所以就会自动设置为InnoDB。
sql-mode配置
sql-mode的配置需要和查看进行配合,因为需要先知道当前的sql-mode模式,并且也是分为三个层级进行配置的:
设置会话级别的sql-mode
mysql> select @@session.sql_mode\G;
*************************** 1. row ***************************
@@session.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
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> set session 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';
Query OK, 0 rows affected (0.04 sec)
mysql>
设置全局级别
这里就只列出命令了,操作流程和结果和会话级别类似
set 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';
配置级别
首先找到配置文件,上面查看的时候有说,然后进行配置
[mysqld]
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER
ok,关于sql-mode就先聊到这里,欢迎各位大佬多多指点啊。