根本原因是doctrine与mysql字符集未统一为utf8mb4,需在doctrine.yaml中配置url参数charset=utf8mb4及use_unicode=true,并在实体字段或全局选项中显式声明utf8mb4字符集与排序规则,同时确保数据库、表、字段层级全部生效。

Symfony 4 执行数据库模型迁移(如 doctrine:migrations:diff 或 doctrine:schema:update)后出现中文乱码,本质不是 Symfony 本身的问题,而是 Doctrine ORM 与 MySQL 字符集协同配置不到位所致。迁移命令只生成或执行 SQL,若底层连接、表定义、字段定义未统一为 utf8mb4,新创建或修改的表/字段仍会沿用旧默认(如 latin1 或残缺的 utf8),导致存入和读取中文时错位解码。
检查并强制 Doctrine 使用 utf8mb4 连接
Doctrine 默认不会主动设置连接字符集,必须显式声明。在 config/packages/doctrine.yaml 中确保包含:
-
url参数中追加&charset=utf8mb4(MySQL 5.7+ 推荐)或?charset=utf8mb4 - 同时启用
use_unicode=true(等价于 JDBC 的useUnicode=true) - 完整示例:
doctrine:<br> dbal:<br> url: 'mysql://user:pass@127.0.0.1:3306/dbname?serverVersion=5.7& charset=utf8mb4& use_unicode=true'
⚠️ 注意:URL 中的 & 是 YAML 转义要求,实际生效的是 &;若使用环境变量拼接 URL,需确保变量值也含该参数。
让迁移生成的表/字段默认用 utf8mb4
Doctrine 默认按数据库服务端配置推断字符集,但不保证字段级继承。需在实体类中显式声明,或全局覆盖:
- 在实体属性上用
@ORM\Column指定:/** @ORM\Column(type="string", length=255, options={"charset":"utf8mb4", "collation":"utf8mb4_unicode_ci"}) */ - 或在
doctrine.yaml中配置全局默认:doctrine:<br> dbal:<br> options:<br> PDO::MYSQL_ATTR_INIT_COMMAND: 'SET NAMES utf8mb4'
- 更稳妥的做法是:迁移前先执行
ALTER DATABASE dbname CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;,确保库级默认值正确
修正已生成但编码错误的迁移文件
若已有迁移类(如 src/Migrations/Version20230101xxxxx.php)创建了 latin1 表,不要直接编辑 SQL 字符串——Doctrine 不解析它。正确做法是:
- 回滚该迁移:
php bin/console doctrine:migrations:execute --down 'Version20230101xxxxx' - 手动修改对应实体类,加入上述
options声明 - 重新生成迁移:
php bin/console doctrine:migrations:diff - 检查新生成的 SQL 是否含
DEFAULT CHARSET=utf8mb4和COLLATE utf8mb4_unicode_ci
验证字段级实际编码是否生效
迁移执行后,不能只看 SHOW CREATE TABLE 里表头的 DEFAULT CHARSET,要确认每个文本字段(VARCHAR, TEXT 等)是否真正用了 utf8mb4:
- 运行:
SHOW FULL COLUMNS FROM your_table_name; - 检查
Collation列是否为utf8mb4_unicode_ci(非latin1_swedish_ci或utf8_general_ci) - 若某字段仍是旧编码,用 Doctrine 命令单独修正:
php bin/console doctrine:query:sql "ALTER TABLE your_table MODIFY column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"











