详解MySQL collation 差异导致的类型比较行为不同
作者:宁小法先森︿( ̄︶ ̄)︿
MySQL数据库查询差异源于collation排序规则不同,本文就来详细的介绍一下MySQL collation 差异导致的类型比较行为不同,感兴趣的可以了解一下
当参数code为int时查询不到 为string时可查询到
CREATE TABLE `users_amoe_record` ( `id` int NOT NULL AUTO_INCREMENT, `user_id` int NOT NULL DEFAULT '0', `key` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `code` char(12) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 初始化;1已创建;3 成功收到来信 4收到但过期 5收到但异常', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `user_id` (`user_id`,`code`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=37494 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
但是另外数据库的数据表, code为int也可以查询到
CREATE TABLE `users_amoe_record` ( `id` int NOT NULL AUTO_INCREMENT, `user_id` int NOT NULL DEFAULT '0', `key` varchar(255) NOT NULL DEFAULT '', `code` char(12) NOT NULL DEFAULT '', `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 初始化;1已创建;3 成功收到来信 4收到但过期 5收到但异常', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `user_id` (`user_id`,`code`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=460090 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
MySQL collation 差异导致的类型比较行为不同
根本原因
两个库的区别:
| 问题库 | 正常库 | |
|---|---|---|
| code 列 collation | utf8mb4_general_ci | utf8mb4_0900_ai_ci |
| MySQL 版本 | 通常 5.7 或早期 8.0 | MySQL 8.0+ 默认 |
当 PHP 通过 PDO 绑定整数参数时:
- utf8mb4_0900_ai_ci:MySQL 8.0 新排序规则,对 CHAR 列和整数的混合类型比较做了正确处理,能找到记录
- utf8mb4_general_ci:旧排序规则,PDO 以 PDO::PARAM_INT 传入整数时,MySQL 对 CHAR(12) 列的类型推导出现偏差,比较失败,查不到记录
本质是:PDO 发送整数类型参数 + CHAR 字符列 + general_ci 排序规则 = MySQL 类型推导错误。
修复方案
在 callback() 里对 $code 强转为字符串,让 PDO 以字符串参数发送,与 CHAR(12) 列类型一致:
Read AmoeService.php (lines 120-129)Edit AmoeService.php
Modified
同理,getCaptcha 里查记录时也用了整数查询,也应该修:
Read AmoeService.php (lines 70-77)
getCaptcha 的查询已经有 (string) 强转,不需要改。只需要修 callback 的这一处。
总结
| 项 | 说明 |
|---|---|
| 根因 | utf8mb4_general_ci 排序规则下,PDO 整数参数无法匹配 CHAR(12) 列 |
| 为什么另一库没问题 | utf8mb4_0900_ai_ci(MySQL 8.0 默认)正确处理了混合类型比较 |
| 修复 | $code = (string)$params["code"] — PDO 以字符串传参,与列类型一致 |
| 诊断日志 | 确认问题后可以清理掉 ioLog("1") 等调试打点 |
到此这篇关于详解MySQL collation 差异导致的类型比较行为不同的文章就介绍到这了,更多相关MySQL collation 差异内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
