thinkphp与mysql版本不兼容的问题处理_sql模式配置与调整

MySQL 8.0+ strict mode 导致 ThinkPHP 插入失败

ThinkPHP 5.x/6.x 在 MySQL 8.0+ 默认开启的 STRICT_TRANS_TABLES 模式下,常报错:Incorrect integer value: ” for column ‘xxx’ at row 1 或 Data too long for column。这不是 ThinkPHP 的 bug,而是 MySQL 对空字符串、隐式类型转换、默认值缺失更严格了。

根本原因是:ThinkPHP 构建的 SQL(比如 insert())可能传入空字符串给 INT 字段,或未显式指定非空字段值,而旧版 MySQL 会自动转成 0 或截断,新版直接拒绝。

临时解决:在数据库连接配置中关闭严格模式(不推荐生产环境)——在 database.php 的 dsn 后追加 ;sql_mode=”正确做法:修改 MySQL 全局或会话级 sql_mode,保留必要校验但移除严格插入限制,例如设为 NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES → 改成 NO_ENGINE_SUBSTITUTION更稳妥:在 ThinkPHP 的 Db::connect() 初始化后,执行一次 Db::execute("SET SESSION sql_mode = ‘NO_ENGINE_SUBSTITUTION’")

ThinkPHP 6.1+ 连接 MySQL 8.0 报 Client does not support authentication protocol

这是 MySQL 8.0 默认使用 caching_sha2_password 认证插件,而老版本 PDO(尤其 PHP 7.2 及以下)不支持。现象是连接直接失败,日志里出现该错误信息。

不能靠升级 PHP(虽然 PHP 7.4+ 增加了部分支持),因为 ThinkPHP 底层仍走 PDO MySQL 驱动,兼容性取决于底层 libmysql 或 mysqlnd 版本。

立即学习“PHP免费学习笔记(深入)”;

首选方案:登录 MySQL,为应用用户重置认证方式:ALTER USER ‘your_user’@’%’ IDENTIFIED WITH mysql_native_password BY ‘your_pass’;避免改全局 default_authentication_plugin(影响其他服务)确认 PHP 编译时用的是 mysqlnd 而非 libmysql(php -i | grep "mysqlnd"),mysqlnd 对新认证协议支持更好

ThinkPHP 时间字段写入 MySQL 8.0 报 Invalid default value for ‘create_time’

MySQL 8.0 默认启用 NO_ZERO_DATE 和 NO_ZERO_IN_DATE,而 ThinkPHP 的模型如果定义了 protected $createTime = ‘create_time’; 且数据库字段是 DATETIME NOT NULL DEFAULT ‘0000-00-00 00:00:00’,就会触发该错误。

本质是 MySQL 拒绝零日期作为有效默认值,而 ThinkPHP 自动生成的时间填充逻辑没适配这个约束。

建表时改用 CURRENT_TIMESTAMP 作默认值:create_time DATETIME DEFAULT CURRENT_TIMESTAMP若无法改表结构,在连接 DSN 中加入 ;sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION(去掉 NO_ZERO_DATE)ThinkPHP 模型中显式设置时间值,避免依赖数据库默认:$data[‘create_time’] = date(‘Y-m-d H:i:s’);

MySQL 5.7 升级到 8.0 后 ThinkPHP 查询结果字段名大小写异常

MySQL 8.0 默认开启 lower_case_table_names=1,但字段名(column name)在结果集中受系统变量 lower_case_field_names 控制;某些 Linux 环境下该值为 0,导致 ThinkPHP 的 select() 返回的数组键名变成全小写(如 user_name → user_name 正常,但 UserName → username),破坏原有驼峰映射逻辑。

这不是 ThinkPHP 自身问题,而是 MySQL 客户端协议返回的元数据字段名被服务端强制小写了。

检查当前值:SELECT @@lower_case_field_names;,若为 0,说明字段名大小写敏感ThinkPHP 中统一用小写字段名访问结果($res[‘user_name’]),别依赖原始大小写避免在 SQL 中用反引号包裹大驼峰字段名(如 `UserName`),这会让结果集键名变成带反引号的字符串,极难处理如需保持字段原样,唯一可靠方式是升级到 ThinkPHP 6.3+ 并启用 pdo_attr => [PDO::ATTR_CASE => PDO::CASE_NATURAL](但仅对 PDO 有效,且依赖驱动支持)

最麻烦的不是配置本身,而是不同环境(开发用 macOS,测试用 CentOS,生产用 Docker)的 lower_case_field_names 值可能不一致,导致本地跑得通,上线就出错。务必在 CI 阶段校验该变量值,并统一建模约定。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。