在开发环境中,使用 Docker Compose 可以快速搭建 MySQL 环境。
但使用挂在目录方式让Docker-MySQL自动执行挂载到目录(/docker-entrypoint-initdb.d)中的初始化脚本, 导入含有中文数据的 SQL 时,我遇到了令人头疼的乱码问题。
咨询了AI, 测试了各种方案之后, 总算解决了这个问题。
本文将完整介绍如何用docker-compose.yml部署mysql:8.0.33,以及如何挂载初始化 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 加上这一行后,中文乱码得到了彻底解决!
- 七、验证字符集是否生效
- 小结
一、基础配置:指定 mysql:8.0.33 镜像
首先,我们在docker-compose.yml文件中明确指定 MySQL 镜像版本。
一定要锁定具体版本号(如
8.0.33),而不是使用latest或宽泛的8.0,以保证多台机器、多次部署的一致性。
生产环境根据情况确定, 一般不推荐使用Docker来部署。
services:mysql:image:mysql:8.0.33container_name:my-mysqlrestart:unless-stoppedenvironment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE:local_databaseTZ:Asia/Shanghaiports:-"3306:3306"二、映射 /docker-entrypoint-initdb.d 目录指定初始化 SQL
MySQL 官方镜像提供了一个非常实用的机制:容器首次启动且数据目录为空时,会自动执行/docker-entrypoint-initdb.d目录下的所有.sql、.sql.gz、.sh文件。
我们只需将本地的初始化 SQL 文件挂载到该目录即可:
volumes:# 持久化数据-mysql_data:/var/lib/mysql# 挂载单个初始化 SQL(关键)-./init.sql:/docker-entrypoint-initdb.d/init.sql也可以挂载整个目录,让多个 SQL 文件按文件名顺序执行:
volumes:-./initdb:/docker-entrypoint-initdb.d⚠️重要提醒:初始化脚本只在数据目录为空时执行一次。如果你修改了 SQL 想重新初始化,需要先删除数据卷:
docker-composedown-v
三、避免乱码:服务端字符集配置
乱码的本质是字符集不统一。
MySQL 8.0 默认字符集虽然已经是utf8mb4,但为了万无一失,需要在服务端、客户端层面都显式声明。
通过command直接指定服务端字符集:
command:---character-set-server=utf8mb4---collation-server=utf8mb4_unicode_ci如果你想用配置文件管理,可以挂载一个自定义的my.cnf:
# my.cnf [mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci [client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4volumes:-./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 示例
services:mysql:image:mysql:8.0.33container_name:my-mysqlrestart:unless-stoppedcommand:---character-set-server=utf8mb4---collation-server=utf8mb4_unicode_cienvironment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE:local_databaseTZ:Asia/Shanghaiports:-"3306:3306"volumes:-mysql_data:/var/lib/mysql-./init.sql:/docker-entrypoint-initdb.d/init.sqlvolumes:mysql_data:六、最后的关键一步:在 SQL 文件中加上SET NAMES utf8mb4;
在完成了上面所有配置后,我以为乱码问题已经解决,但实际导入时中文依然出现乱码。经过反复排查,我在初始化 SQL 文件的最开头加上了这一行:
SETNAMES utf8mb4;-- init.sqlSETNAMES utf8mb4;CREATETABLEIFNOTEXISTS`user`(`id`INTPRIMARYKEYAUTO_INCREMENT,`name`VARCHAR(50)NOTNULL)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;INSERTINTO`user`(`name`)VALUES('张三'),('李四'),('王五');6.1 加上这一行后,中文乱码得到了彻底解决!
为什么这一步如此关键?因为SET NAMES utf8mb4;会同时设置当前连接会话的三个核心字符集变量:
character_set_client(客户端发送数据的字符集)character_set_connection(连接层的字符集)character_set_results(返回结果的字符集)
即使前面服务端和配置文件都做了设置,但初始化导入这个会话如果没有显式声明连接字符集,仍可能因默认值不匹配导致中文在传输过程中被错误解码。SET NAMES utf8mb4;直接在 SQL 执行的会话层面"一锤定音",从源头保证了中文数据以 utf8mb4 正确写入。
七、验证字符集是否生效
部署完成后,进入容器验证:
dockerexec-itmy-mysql mysql-uroot-p\-e"SHOW VARIABLES LIKE 'character%';"确认以下变量均为utf8mb4:
character_set_servercharacter_set_databasecharacter_set_clientcharacter_set_connection
再查询数据,确认中文显示正常:
SELECT*FROMuser;小结
最终在 SQL 文件首行加上SET NAMES utf8mb4;,才让中文乱码问题得到了彻底、干净的解决。