Docker 部署后 MySQL 中文变问号排查实录
环境:MySQL 8.0 容器 + Flask + docker-compose,种子数据来自 db.sql。
1. 现象
SYS_SITE_CONFIG 等表中文全变 ?,但 © 正常:
1 SELECT * FROM SYS_SITE_CONFIG LIMIT 3;
1 2 3 4 5 6 7 +---------------------+---------------------------------------------+---------------+ | config_key | config_value | description | +---------------------+---------------------------------------------+---------------+ | sys.site.copyright | Copyright © 2026 ???? All Rights Reserved. | ????????? | | sys.site.loginDesc | ????????????????????????????????????? | ????????? | | sys.site.loginTitle | ?????? | ????????????? | +---------------------+---------------------------------------------+---------------+
2. 初步怀疑:表/库字符集 1 2 3 SHOW CREATE TABLE SYS_SITE_CONFIG\G SELECT HEX(LEFT(config_value,12)) AS hex_head FROM SYS_SITE_CONFIG WHERE config_key='sys.site.loginDesc' \G SELECT @@character_set_database;
1 2 3 4 5 6 7 Create Table: CREATE TABLE `SYS_SITE_CONFIG` (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci hex_head: 3F3F3F3F3F3F3F3F3F3F3F3F +--------------------------+ | @@character_set_database | +--------------------------+ | utf8mb4 | +--------------------------+
结论 :表和库都是 utf8mb4,但 HEX 全是 3F(ASCII ?),说明中文在写入时就被物理替换 ,不是显示问题。
db.sql 本身没问题:
1 2 3 4 file -i db.sql grep -c "集打卡" db.sql
3. 文件字节是否正确 1 2 3 4 5 6 grep "sys.site.loginDesc" db.sql | od -An -tx1 | head docker compose exec mysql bash -c "grep \"sys.site.loginDesc\" /docker-entrypoint-initdb.d/01-init.sql | od -An -tx1 | head"
再查库里同一段:
1 2 3 docker compose exec mysql mysql -uroot -p'***' --default-character-set=utf8mb4 your_db \ -e "SELECT HEX(config_value) FROM SYS_SITE_CONFIG WHERE config_key='sys.site.loginDesc';"
=> 文件进容器是好的,但 mysql < db.sql 这一步把有效 UTF-8 写成了 ?。
4. 连接字符集是否正常 1 2 docker compose exec mysql mysql -uroot -p'***' --default-character-set=utf8mb4 your_db \ -e "SHOW VARIABLES LIKE 'character_set%';"
1 2 3 4 5 6 +--------------------------+--------------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_server | utf8mb4 | +--------------------------+
服务端全是 utf8mb4,但最小化写入却正常:
1 docker compose exec mysql bash -c "mysql -uroot -p'***' --default-character-set=utf8mb4 your_db -e \"SET NAMES utf8mb4; INSERT INTO SYS_SITE_CONFIG (config_key, config_value) VALUES ('test.chinese','集打卡') ON DUPLICATE KEY UPDATE config_value='集打卡'; SELECT config_value, HEX(config_value) FROM SYS_SITE_CONFIG WHERE config_key='test.chinese';\""
1 2 3 4 5 +--------------+--------------------+ | config_value | HEX(config_value) | +--------------+--------------------+ | 集打卡 | E99B86E68993E58DA1 | +--------------+--------------------+
结论 :服务端能存中文,问题只在 docker compose exec -T mysql ... < db.sql 这种宿主机管道 。
5. 根因 docker compose exec -T 的 stdin 在当前环境下会对中文做文本转码,导致有效 UTF-8 进到 mysql 客户端前就被替换为 ?。错误路径:
1 2 3 4 主机 db.sql (UTF-8 正确) → docker exec -T stdin 管道(转码) → mysql 客户端(收到已是 3F) → 存库 3F
而直接字符串 INSERT '集打卡' 不走管道,所以正常。
6. 修复 拷进容器再导,绕开管道:
1 2 3 4 5 docker compose exec mysql mysql -uroot -p'***' -e "DROP DATABASE your_db; CREATE DATABASE your_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;" docker cp db.sql $(docker compose ps -q mysql):/tmp/db.sql docker compose exec mysql bash -c "mysql -uroot -p'***' --default-character-set=utf8mb4 your_db < /tmp/db.sql" docker compose exec mysql mysql -uroot -p'***' --default-character-set=utf8mb4 your_db \ -e "SELECT config_value FROM SYS_SITE_CONFIG WHERE config_key='sys.site.loginDesc';"
1 2 3 +-----------------------------------------------------------------------------------------------------------------+ | 集打卡、考勤、业绩统计于一体的现代化直播运营平台,简洁高效,助力团队协作。 | +-----------------------------------------------------------------------------------------------------------------+
7. 自动化避免复发 docker-compose.yml 改为首次建库时容器内导入:
1 2 3 4 volumes: - mysql-data:/var/lib/mysql - ./db.sql:/tmp/db.sql:ro - ./docker/mysql-init.sh:/docker-entrypoint-initdb.d/01-init.sh:ro
docker/mysql-init.sh:
1 2 3 #!/bin/bash set -emysql --default-character-set=utf8mb4 -uroot -p"$MYSQL_ROOT_PASSWORD " "$MYSQL_DATABASE " < /tmp/db.sql
新部署 docker compose down -v && docker compose up -d 自动正确;已有库的重导仍用上面的 docker cp 方式,并始终加 --default-character-set=utf8mb4。
8. 教训
3F 的 HEX 且 © 正常,是写入时转码的典型特征(中文映射不到目标字符集)。
SHOW CREATE TABLE 和 character_set% 都正常时,重点查导入管道 ,而非表结构。
db.sql 保持 UTF-8 无 BOM,用 scp/git 传输,别用会转码的在线编辑器。