doctrine dsn 中必须显式写 charset=utf8mb4,仅靠 set names utf8mb4 或 pdo::mysql_attr_init_command 不起作用;mysql 服务端 character_set_server、database、client 三者也须统一为 utf8mb4,否则仍会乱码。

Doctrine DSN 中必须显式写 charset=utf8mb4
只靠 SET NAMES utf8mb4 或 PDO::MYSQL_ATTR_INIT_COMMAND 不起作用——PHP 7.2+ 的 PDO 在连接建立时就锁定字符集,DSN 缺失 charset=utf8mb4 会导致插入 emoji 或生僻汉字直接报 Incorrect string value。
-
DATABASE_URL必须包含?charset=utf8mb4,例如:mysql://root:pass@127.0.0.1:3306/app?serverVersion=10.11&charset=utf8mb4 - 不能写成
utf8、UTF8MB4或漏掉=;大小写敏感,拼错就失效 - 如果用
parameters.yml配置,也要在doctrine.dbal下手动加charset: utf8mb4字段,否则 Doctrine 不会自动从 DSN 提取
MySQL 服务端三处字符集必须统一为 utf8mb4
应用层设对了,但 MySQL 服务端还是 latin1 或 utf8(即 utf8mb3),照样乱码。关键不是“有没有”,而是“全链路是否一致”。
- 检查:执行
SHOW VARIABLES LIKE 'character_set_%',确认character_set_server、character_set_database、character_set_client全是utf8mb4 - 修改
/etc/my.cnf的[mysqld]段:character-set-server = utf8mb4和collation-server = utf8mb4_unicode_ci - 已有数据库和表需单独转换:
ALTER DATABASE mydb CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci,再对每张表执行ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
Symfony 生产环境要关掉 auto_generate_proxy_classes
开发时开着它方便调试,但生产环境开启会导致每次请求都尝试生成代理类,不仅慢,还可能因权限或临时目录问题中断连接,间接让字符集配置“看似生效实则失效”。
- 在
config/packages/prod/doctrine.yaml中显式关闭:doctrine.orm.auto_generate_proxy_classes: false - 同时设置
doctrine.dbal.options加上PDO::ATTR_TIMEOUT: 5,避免连接卡住后超时重试导致编码上下文丢失 - 别忘了清空 prod 缓存:
php bin/console cache:clear --env=prod,否则旧的连接参数可能被缓存住
验证是否真正生效的三个命令
光看配置文件不等于跑通。必须用实际 SQL 和连接行为交叉验证。
- 运行
php bin/console doctrine:database:create --if-not-exists,成功不代表字符集对——它只建库,不设 charset - 执行
php bin/console doctrine:schema:update --force后,查一张新表的建表语句:SHOW CREATE TABLE student,确认DEFAULT CHARSET=utf8mb4出现在输出里 - 连进 MySQL 执行
SELECT @@character_set_client, @@character_set_connection, @@character_set_results,三个值必须全是utf8mb4,缺一不可
INSERT。











