前两天在阿里云服务器上搭建了本身的博客,一切都很顺利,今天在点击归档按钮时,发现是报404。因而我把solo代码在本地运行起来,用本地的mysql数据库,看是否有一样的问题,结果是能够正常访问的。那就看看服务器上的solo日志呗,结果发现了如下报错:前端
Caused by: org.b3log.latke.repository.RepositoryException: java.sql.SQLSyntaxErrorException: Expression #20 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'solo.aa.oId' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
原来,这个问题出如今MySQL5.7后版本上,默认的sql_mode值是这样的:java
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
那么sql_mode 有哪些配置?都表明什么意思?python
ONLY_FULL_GROUP_BY mysql
对于GROUP BY聚合操做,若是在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,由于列不在GROUP BY从句中。简而言之,就是SELECT后面接的列必须被GROUP BY后面接的列所包含。如:面试
select a,b from table group by a,b,c; (正确) select a,b,c from table group by a,b; (错误)
这个配置会使得GROUP BY语句环境变得十分狭窄,因此通常都不加这个配置spring
该值影响自增加列的插入。默认设置下,插入0或NULL表明生成下一个自增加值。(不信的能够试试,默认的sql_mode你在自增主键列设置为0,该字段会自动变为最新的自增值,效果和null同样),若是用户但愿插入的值为0(不改变),该列又是自增加的,那么这个选项就有用了。sql
在该模式下,若是一个值不能插入到一个事务表中,则中断当前的操做,对非事务表不作限制。(InnoDB默认事务表,MyISAM默认非事务表;MySQL事务表支持将批处理当作一个完整的任务统一提交或回滚,即对包含在事务中的多条语句要么全执行,要么所有不执行。非事务表则不支持此种操做,批处理中的语句若是遇到错误,在错误前的语句执行成功,以后的则不执行;MySQL事务表有表锁与行锁非事务表则只有表锁)docker
在严格模式下,不容许日期和月份为零shell
设置该值,mysql数据库不容许插入零日期,插入零日期会抛出错误而不是警告。数据库
在INSERT或UPDATE过程当中,若是数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL
禁止GRANT建立密码为空的用户
若是须要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常
将”||”视为字符串的链接操做符而非或运算符,这和Oracle数据库是同样的,也和字符串的拼接函数Concat相相似
启用ANSI_QUOTES后,不能用双引号来引用字符串,由于它被解释为识别符
本地起一个数据库,先查看sql_mode模式:
mysql> select @@global.sql_mode; +--------------------------------------------+ | @@global.sql_mode | +--------------------------------------------+ | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | +--------------------------------------------+ 1 row in set (0.00 sec) mysql> select @@session.sql_mode; +--------------------------------------------+ | @@session.sql_mode | +--------------------------------------------+ | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | +--------------------------------------------+ 1 row in set (0.00 sec)
建立一个测试的表:
mysql> CREATE TABLE IF NOT EXISTS `demo`( -> `id` INT UNSIGNED AUTO_INCREMENT, -> `rank` VARCHAR(100) NOT NULL, -> `name` VARCHAR(40) NOT NULL, -> `gender` TINYINT NOT NULL, -> PRIMARY KEY ( `id` ) -> )ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.02 sec) mysql> mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | demo | +----------------+ 1 row in set (0.00 sec) mysql> desc demo; +--------+------------------+------+-----+---------+------------ | Field | Type | Null | Key | Default | Extra +--------+------------------+------+-----+---------+------------ | id | int(10) unsigned | NO | PRI | NULL | auto_increm | rank | varchar(100) | NO | | NULL | | name | varchar(40) | NO | | NULL | | gender | tinyint(4) | NO | | NULL | +--------+------------------+------+-----+---------+------------ 4 rows in set (0.01 sec)
插入测试数据:
mysql> insert into demo values(1, 'A', 'coderaction1', '20'); Query OK, 1 row affected (0.01 sec) mysql> insert into demo values(2, 'B', 'coderaction2', '21'); Query OK, 1 row affected (0.00 sec) mysql> insert into demo values(3, 'A', 'coderaction3', '22'); Query OK, 1 row affected (0.00 sec) mysql> insert into demo values(4, 'C', 'coderaction4', '23'); Query OK, 1 row affected (0.00 sec) mysql> insert into demo values(5, 'A', 'coderaction5', '21'); Query OK, 1 row affected (0.00 sec) mysql> insert into demo values(6, 'C', 'coderaction6', '28'); Query OK, 1 row affected (0.01 sec) mysql> mysql> select * from demo; +----+------+--------------+--------+ | id | rank | name | gender | +----+------+--------------+--------+ | 1 | A | coderaction1 | 20 | | 2 | B | coderaction2 | 21 | | 3 | A | coderaction3 | 22 | | 4 | C | coderaction4 | 23 | | 5 | A | coderaction5 | 21 | | 6 | C | coderaction6 | 28 | +----+------+--------------+--------+ 6 rows in set (0.00 sec)
分别执行如下sql命令:
mysql> select count(id) from demo order by rank; +-----------+ | count(id) | +-----------+ | 6 | +-----------+ 1 row in set (0.01 sec) mysql> select count(id) from demo group by rank; +-----------+ | count(id) | +-----------+ | 3 | | 1 | | 2 | +-----------+ 3 rows in set (0.00 sec) mysql> select count(rank),id from demo group by rank; +-------------+----+ | count(rank) | id | +-------------+----+ | 3 | 1 | | 1 | 2 | | 2 | 4 | +-------------+----+ 3 rows in set (0.00 sec) mysql> select count(rank),id from demo group by id; +-------------+----+ | count(rank) | id | +-------------+----+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 1 | 5 | | 1 | 6 | +-------------+----+ 6 rows in set (0.00 sec) mysql>
能够看到上面四个sql都执行成功。
修改sql_mode,临时修改sql_mode方式有两种,一种是设置当前会话链接的session级别的sql_mode,另外一个是global级别的sql_mode。
先来看看session级别的sql_mode,设置方式有两种:
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.00 sec) 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.00 sec) mysql> select @@session.sql_mode; +-------------------------------------------------------------------------------------------------------------------------------------------+ | @@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)
设置session级别sql_mode,当前session级别查询到新的,下次重连后失效。
再看看global级别的sql_mode,设置方式有两种:
mysql> set @@global.sql_mode='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.00 sec) mysql> set global sql_mode='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.00 sec) mysql> select @@global.sql_mode; +------------------------------------------------------------------------------------------------------------------------+ | @@global.sql_mode | +------------------------------------------------------------------------------------------------------------------------+ | 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)
设置global级别sql_mode,当前session级别查询到仍是旧的,因此执行命令时,仍是按照旧配置。下次重连后利用新配置。
当咱们设置完上面session级别的sql_mode,在其中加ONLY_FULL_GROUP_BY后,执行测试sql语句报错:
mysql> select count(rank),id from demo group by rank; ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.demo.id' which is not functionally dependen t on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by mysql> select count(rank),id from demo group by id; +-------------+----+ | count(rank) | id | +-------------+----+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 1 | 5 | | 1 | 6 | +-------------+----+ 6 rows in set (0.00 sec)
这也验证了:SELECT后面接的列必须被GROUP BY后面接的列所包含。
注意:经过session和global设置临时生效的,即当mysql重启后,都会失效。须要在mysql启动配置文件中默认设置。
除了上面测试时用到的临时解决的两种方法。要想mysql重启后依然生效,须要在mysql的配置文件,通常是my.cnf中的[mysqld]下面加sql_mode配置。由于我使用的是k8s部署的mysql,镜像安装和在宿主机上经过软件包安装有必定差异。但最终仍是更改的my.cnf。
kubectl exec -ti mysql-75797cf796-84rdl bash root@mysql-75797cf796-84rdl:/# root@mysql-75797cf796-84rdl:/# cat /etc/mysql/my.cnf # Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. # ..... !includedir /etc/mysql/conf.d/ !includedir /etc/mysql/mysql.conf.d/
能够看到这里包含了两个目录下的文件,查看一下,mysql.conf.d下,发现有咱们须要更改的文件
cat /etc/mysql/mysql.conf.d/mysqld.cnf
查看并将该文件用kubectl cp命令拷贝到宿主机上,修改后最终要挂载进入pod里。
kubectl cp default/mysql-75797cf796-84rdl:/etc/mysql/mysql.conf.d/mysqld.cnf /data/blog-solo/mysql-config/mysqld.cnf
修改后文件以下,主要关注sql_mode
root@mysql-75797cf796-84rdl:/# cd /etc/mysql/mysql.conf.d/ root@mysql-75797cf796-84rdl:/etc/mysql/mysql.conf.d# ls -l total 4 -rw-r--r-- 1 root root 1671 Oct 26 11:40 mysqld.cnf root@mysql-75797cf796-84rdl:/etc/mysql/mysql.conf.d# cat mysqld.cnf # Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. # ... [mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION #log-error = /var/log/mysql/error.log # By default we only accept connections from localhost #bind-address = 127.0.0.1 # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 root@mysql-75797cf796-84rdl:/etc/mysql/mysql.conf.d#
最后修改mysql-deployment:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: mysql spec: replicas: 1 template: metadata: labels: name: mysql spec: containers: - name: mysql image: mysql:5.7.28 imagePullPolicy: IfNotPresent ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD value: "password" volumeMounts: - name: mysql-config mountPath: /etc/mysql/mysql.conf.d - name: mysql-data mountPath: /var/lib/mysql volumes: - name: mysql-config hostPath: path: /data/blog-solo/mysql-config/ - name: mysql-data hostPath: path: /data/blog-solo/mysql-data/
注意要把配置文件和数据都挂载到宿主机上,不然pod重启后就会丢失配置和数据。
docker 下修改 mysql sql_mode和配置文件
记一次Group by 查询时的ONLY_FULL_GROUP_BY错误以及后续
本公众号免费提供csdn下载服务,海量IT学习资源若是你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时咱们组建了一个技术交流群,里面有不少大佬,会不定时分享技术文章,若是你想来一块儿学习提升,能够公众号后台回复【2】,免费邀请加技术交流群互相学习提升,会不按期分享编程IT相关资源。
扫码关注,精彩内容第一时间推给你