必须在database_url中显式添加&charset=utf8mb4,否则doctrine默认使用latin1或服务端旧值,导致emoji和四字节中文插入失败;同时需确保mysql服务端character_set_server为utf8mb4、serverversion严格匹配实际版本(如8.0),三者缺一不可。

DATABASE_URL里必须显式加charset=utf8mb4
Doctrine不会自动推断字符集,不写就默认用latin1或服务端默认值,导致存emoji、四字节中文时被截断或报错Incorrect string value。在.env中配置DATABASE_URL时,必须把&charset=utf8mb4追加到连接串末尾:
DATABASE_URL="mysql://root:pass%40word@127.0.0.1:3306/symfony?serverVersion=8.0&charset=utf8mb4"
-
charset=utf8mb4要带&前缀,不能漏掉 - MySQL 5.7+ 默认支持
utf8mb4,但老版本需确认my.cnf里有character-set-server = utf8mb4 - URL 编码的
&要写成&,否则 Symfony 解析失败
MySQL服务端也要配对启用utf8mb4
只改DATABASE_URL不够——如果MySQL实例本身没启用utf8mb4,连接成功了,建表时仍可能回退到utf8(其实是utf8mb3),或者插入时报Specified key was too long。
- 检查当前配置:
mysql -u root -p -e "SHOW VARIABLES LIKE 'character_set%';" - 关键变量应为:
character_set_server = utf8mb4、collation_server = utf8mb4_unicode_ci - 若不匹配,修改
/etc/mysql/my.cnf(或mysqld.cnf),在[mysqld]段下添加两行 - 重启MySQL:
sudo systemctl restart mysql(Ubuntu/Debian)
迁移生成的表默认用utf8mb4吗?
不一定。Doctrine迁移是否生成utf8mb4表,取决于三个条件是否同时满足:
-
DATABASE_URL里含&charset=utf8mb4 - MySQL服务端
character_set_server是utf8mb4 - 实体字段没显式指定
options={"collation"="utf8mb3_general_ci"}这类覆盖项
验证方法:执行php bin/console doctrine:migrations:migrate后,进MySQL查表结构:SHOW CREATE TABLE user;——看DEFAULT CHARSET是不是utf8mb4,以及VARCHAR字段的COLLATE是否为utf8mb4_unicode_ci。
为什么serverVersion也影响字符集行为?
MySQL 8.0 对utf8mb4的默认排序规则(collation)做了变更,比如utf8mb4_0900_ai_ci。如果DATABASE_URL里serverVersion=8.0写成5.7,Doctrine会按旧规则生成SQL,可能导致迁移失败或排序异常。
- 用
mysql --version确认实际版本 -
serverVersion必须严格匹配,不能省略也不能估摸着写 - 若用Docker MySQL 8.0镜像,默认
collation_server是utf8mb4_0900_ai_ci,此时建议在DATABASE_URL里额外加&collation=utf8mb4_unicode_ci保持兼容
DATABASE_URL和my.cnf都配对了,只要serverVersion写错,Doctrine生成的迁移SQL仍可能绕过utf8mb4语义——比如建索引时字段长度超限却不报错,上线后才发现搜索失效。











