• 技术文章 >php框架 >Laravel

    关于laravel解决mysql only_full_group_by问题

    藏色散人藏色散人2021-01-26 09:10:55转载557

    下面由Laravel教程栏目给大家介绍laravel解决mysql only_full_group_by问题的方法,希望对需要的朋友有所帮助!

    MySQL 5.7 之后 only_full_group_by 默认是开启的,这就导致 sql 的检测更加严格,将导致报下面的错

    SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'edu.t_sounds.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

    解决这个问题也走了不少弯路,按照网上找的方式一个一个试

    解决思路

    查看 sql_mode

    select @@GLOBAL.sql_mode;SELECT @@SESSION.sql_mode

    首先查看并修改 mysql 配置文件,my.cnf 很尴尬我的这个里面并没有 ONLY_FULL_GROUP_BY

    [mysqld]sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

    不行,就接着来,想到mysql 有服务端配置,和客户端配置之分,那就增加 [client] 配置

    [client]sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

    重启mysql ,在MySQL工具查看 sql_mode,确实显示结果和配置的是一样的,但是程序依然报同样的错

    又是一番查找,突然意识到 global session 的问题,也就是文章头部放的两条查询 sql_mode 的语句,就查询一下 是啥区别

    mysql 变量设置方式分两种,
    一种全局配置,也就是 global,作用于全局;
    一种会话配置 session, 只作用于当前连接

    会不会是laravel 在当前连接设置了 sql_mode

    在 laravel 程序打印 sql_mode

    $result = \DB::select('SELECT @@GLOBAL.sql_mode');
    print_r($result);exit;
    结果:
    STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
    
    $result = \DB::select('SELECT @@SESSION.sql_mode');
    print_r($result);exit;
    结果:
    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

    找到了原来是程序设置了

    第一想到 mysql 的配置有一个严格模式,我一直是开启状态,设置为 false 问题顺利解决

    'strict' => false,

    在 vendor/laravel/framework/src/ILLuminate/Database 文件夹下搜索 strict ,直接找到核心代码

    文件:vendor/laravel/framework/src/ILLuminate/Database/Connectors/MySqlConnector.php

    protected function setModes(PDO $connection, array $config){
        if (isset($config['modes'])) {
            $this->setCustomModes($connection, $config);
        } elseif (isset($config['strict'])) {
            if ($config['strict']) {
                $connection->prepare($this->strictMode($connection))->execute();
            } else {
                $connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();
            }
        }}

    第一个判断直接判断是否存在 modes 配置,有的话就直接使用这个

    来,搞一下

    'modes' => ['STRICT_TRANS_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'ERROR_FOR_pISION_BY_ZERO', 'NO_AUTO_CREATE_USER', 'NO_ENGINE_SUBSTITUTION'],

    测试,直接问题搞定

    本着寻根刨底的精神,再接着往下看

    如果 strict = true

    将直接设置程序中写死的 sql_mode, laravel 区分了 mysql 8.0.11 和别的版本

    protected function strictMode(PDO $connection)
    {
        if (version_compare($connection->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11') >= 0) {
            return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
        }
    
        return "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'";
    }

    再接着 如果 strict = false ,直接将 sql_mode 设置为NO_ENGINE_SUBSTITUTION

    $connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();

    到这里问题就彻底解决了

    最终解决方式

    'strict' => true,
    'modes' => ['STRICT_TRANS_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'ERROR_FOR_DIVISION_BY_ZERO', 'NO_AUTO_CREATE_USER', 'NO_ENGINE_SUBSTITUTION'],

    保留了 strict = true,增加 modes 选项,里面的参数是 laravel 底层的配置,只是去掉了 ONLY_FULL_GROUP_BY

    总结:走了不少弯路,也花了不少时间,最终问题解决,并且并不需要修改 mysql 的任何配置

    以上就是关于laravel解决mysql only_full_group_by问题的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:learnku,如有侵犯,请联系admin@php.cn删除
    专题推荐:laravel
    上一篇:你会用Laravel的这10种用法吗? 下一篇:Laravel如何优雅填充SQL数据
    大前端线上培训班

    相关文章推荐

    • 总结Laravel事件系统用法(监听事件,观察者模式)• 最简单的laravel配置多域名方法• 关于Laravel使用MongoDB复杂的查询• 分享一种Laravel异常上下文解决方案• 你会用Laravel的这10种用法吗?

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网