前兩天在阿里雲服務器上搭建了本身的博客,一切都很順利,今天在點擊歸檔按鈕時,發現是報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相關資源。
掃碼關注,精彩內容第一時間推給你