根本原因是utf8mb4未贯穿全链路:mysql服务端character_set_server必须为utf8mb4,dsn中必须硬写charset=utf8mb4(database.php的'charset'配置无效),表与字段需显式设为utf8mb4字符集及校对规则,并清除php文件bom头。

ThinkPHP数据库读取中文或emoji显示为???、乱码字符(如)、或四字节字符被截断,根本原因不是“没设utf8”,而是utf8mb4没贯穿全链路——从MySQL服务端到PDO连接、再到表结构与字段定义,任何一环掉链子都会出问题。
DSN里必须硬写charset=utf8mb4,database.php里的'charset'配置无效
ThinkPHP5/6 的 'charset' => 'utf8mb4' 配置项只在 PDO 构造时尝试注入 DSN,但一旦你手动写了 dsn 字段(比如带 host/dbname),这个配置就完全被忽略。更麻烦的是,某些旧版 mysqlnd 驱动压根不认它。
- 删掉
database.php中所有形如'charset' => 'utf8'或'charset' => 'utf8mb4'的行,避免干扰 - 直接在
'dsn'字段中写死:'dsn' => 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4' - 别用
utf8——MySQL 的utf8是utf8mb3,不支持 emoji 和生僻汉字,存进去就是???
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true 解决 SQLSTATE[HY000]: General error: 2014
这个错误本质是未缓冲查询冲突:你在前一个 SELECT 的结果集还没取完(比如用 foreach 迭代中),又发了新查询(比如嵌套查关联表),PDO 默认不缓存结果,MySQL 服务端还拿着游标,直接报错。
- 在
database.php的'params'中加:PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true - 别写成字符串键名,例如
'MYSQL_ATTR_USE_BUFFERED_QUERY'—— 这是常见拼写错误,必须用常量全名 -
PDO::ATTR_EMULATE_PREPARES => true能间接缓解,但不如开缓冲稳定;fetchAll()只是临时补救,不能替代连接层配置
MySQL服务端必须设 character_set_server=utf8mb4,否则SET NAMES也白搭
哪怕 DSN 写对了 charset=utf8mb4,只要 MySQL 的 character_set_server 还是 latin1 或 utf8,新建库/表/字段默认就不用 utf8mb4,插入四字节字符必然失败,报 SQLSTATE[HY000]: General error: 1366 Incorrect string value。
- 执行
SHOW VARIABLES LIKE 'character_set_server';,值必须是utf8mb4 - 没生效就改
my.cnf(Linux)或my.ini(Windows),加一行:character-set-server = utf8mb4,然后重启mysqld - ThinkPHP6 不会自动执行
SET NAMES utf8mb4,得手动补:在app/common.php或连接回调里加Db::connect()->execute('SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci');
已有表字段不升级,连对了也照样乱码
TP6 的 Schema::table() 或迁移命令不会继承你配的 charset,也不会自动补 COLLATE。原表是 utf8,新增字段默认还是 utf8,哪怕你连的是 utf8mb4 连接。
- 建新表时必须链式调用:
->engine('InnoDB')->charset('utf8mb4')->collation('utf8mb4_unicode_ci') - 改已有字段:
Db::statement("ALTER TABLE `users` MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci") - 整表升级更彻底:
Db::statement("ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"),注意带CONVERT TO,否则只是改默认值,不改现有字段
最易被忽略的一点:BOM 头。VS Code 或 Notepad++ 保存 PHP 文件时若选了 “UTF-8 with BOM”,会导致 header() 失败、输出提前,后续所有编码设置都失效——echo 出来的 HTML 会被浏览器 fallback 成 ISO-8859-1,再 utf8 的数据也显示成 。务必确认所有 PHP 文件是纯 UTF-8(无 BOM)。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











