在开发环境中,使用 Docker Compose 可以快速搭建 MySQL 环境。
但使用挂在目录方式让Docker-MySQL自动执行挂载到目录(/docker-entrypoint-initdb.d)中的初始化脚本, 导入含有中文数据的 SQL 时,我遇到了令人头疼的乱码问题。
咨询了AI, 测试了各种方案之后, 总算解决了这个问题。
本文将完整介绍如何用 docker-compose.yml 部署 mysql:8.0.33,以及如何挂载初始化 SQL,并 彻底解决中文乱码 问题。
### 文章目录
- [@toc](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [一、基础配置:指定 mysql:8.0.33 镜像](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [三、避免乱码:服务端字符集配置](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [四、初始化 SQL 文件本身的编码](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [五、完整的 docker-compose.yml 示例](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [六、最后的关键一步:在 SQL 文件中加上 `SET NAMES utf8mb4;`](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [6.1 加上这一行后,中文乱码得到了彻底解决!](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [七、验证字符集是否生效](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结) - [小结](#文章目录 @[toc] 一、基础配置:指定 mysql:8.0.33 镜像 二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL 三、避免乱码:服务端字符集配置 四、初始化 SQL 文件本身的编码 五、完整的 docker-compose.yml 示例 六、最后的关键一步:在 SQL 文件中加上
SET NAMES utf8mb4;6.1 加上这一行后,中文乱码得到了彻底解决! 七、验证字符集是否生效 小结)
一、基础配置:指定 mysql:8.0.33 镜像
首先,我们在 docker-compose.yml 文件中明确指定 MySQL 镜像版本。
一定要锁定具体版本号 (如
8.0.33),而不是使用latest或宽泛的8.0,以保证多台机器、多次部署的一致性。
生产环境根据情况确定, 一般不推荐使用Docker来部署。
yaml
services:
mysql:
image: mysql:8.0.33
container_name: my-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: local_database
TZ: Asia/Shanghai
ports:
- "3306:3306"
二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL
MySQL 官方镜像提供了一个非常实用的机制: 容器首次启动且数据目录为空时 ,会自动执行 /docker-entrypoint-initdb.d 目录下的所有 .sql、.sql.gz、.sh 文件。
我们只需将本地的初始化 SQL 文件挂载到该目录即可:
yaml
volumes:
# 持久化数据
- mysql_data:/var/lib/mysql
# 挂载单个初始化 SQL(关键)
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
也可以挂载整个目录,让多个 SQL 文件按文件名顺序执行:
yaml
volumes:
- ./initdb:/docker-entrypoint-initdb.d
⚠️ 重要提醒 :初始化脚本只在数据目录为空时执行一次。如果你修改了 SQL 想重新初始化,需要先删除数据卷:
bashdocker-compose down -v
三、避免乱码:服务端字符集配置
乱码的本质是 字符集不统一。
MySQL 8.0 默认字符集虽然已经是 utf8mb4,但为了万无一失,需要在服务端、客户端层面都显式声明。
通过 command 直接指定服务端字符集:
yaml
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
如果你想用配置文件管理,可以挂载一个自定义的 my.cnf:
ini
# my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
yaml
volumes:
- ./my.cnf:/etc/mysql/conf.d/my.cnf
其中 [client] 和 [mysql] 这两段尤其重要,因为容器在执行 /docker-entrypoint-initdb.d 里的 SQL 时,正是通过内置的 mysql 客户端导入的。如果客户端连接字符集不对,导入的中文就会乱码。
四、初始化 SQL 文件本身的编码
除了 MySQL 的配置,还要确保 SQL 文件本身的物理编码正确:
- 文件必须保存为 UTF-8 编码(无 BOM)
- 不要使用 GBK、ANSI 等编码保存含中文的 SQL 文件
可以用编辑器(如 VS Code)右下角确认并切换编码格式。
五、完整的 docker-compose.yml 示例
yaml
services:
mysql:
image: mysql:8.0.33
container_name: my-mysql
restart: unless-stopped
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: local_database
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
mysql_data:
六、最后的关键一步:在 SQL 文件中加上 SET NAMES utf8mb4;
在完成了上面所有配置后,我以为乱码问题已经解决,但实际导入时中文依然出现乱码 。经过反复排查,我在初始化 SQL 文件的最开头加上了这一行:
sql
SET NAMES utf8mb4;
sql
-- init.sql
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` (`name`) VALUES ('张三'), ('李四'), ('王五');
6.1 加上这一行后,中文乱码得到了彻底解决!
为什么这一步如此关键?因为 SET NAMES utf8mb4; 会 同时设置当前连接会话的三个核心字符集变量:
character_set_client(客户端发送数据的字符集)character_set_connection(连接层的字符集)character_set_results(返回结果的字符集)
即使前面服务端和配置文件都做了设置,但初始化导入这个会话 如果没有显式声明连接字符集,仍可能因默认值不匹配导致中文在传输过程中被错误解码。SET NAMES utf8mb4; 直接在 SQL 执行的会话层面"一锤定音",从源头保证了中文数据以 utf8mb4 正确写入。
七、验证字符集是否生效
部署完成后,进入容器验证:
bash
docker exec -it my-mysql mysql -uroot -p \
-e "SHOW VARIABLES LIKE 'character%';"
确认以下变量均为 utf8mb4:
character_set_servercharacter_set_databasecharacter_set_clientcharacter_set_connection
再查询数据,确认中文显示正常:
sql
SELECT * FROM user;
小结
最终在 SQL 文件首行加上 SET NAMES utf8mb4;,才让中文乱码问题得到了彻底、干净的解决。