Docker-Compose 部署 MySQL 8 并解决中文乱码问题
在开发环境中使用 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 加上这一行后中文乱码得到了彻底解决七、验证字符集是否生效小结一、基础配置指定 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 目录指定初始化 SQLMySQL 官方镜像提供了一个非常实用的机制容器首次启动且数据目录为空时会自动执行/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-serverutf8mb4---collation-serverutf8mb4_unicode_ci如果你想用配置文件管理可以挂载一个自定义的my.cnf# my.cnf [mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci [client] default-character-setutf8mb4 [mysql] default-character-setutf8mb4volumes:-./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-serverutf8mb4---collation-serverutf8mb4_unicode_cienvironment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE:local_databaseTZ:Asia/Shanghaiports:-3306:3306volumes:-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;CREATETABLEIFNOTEXISTSuser(idINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(50)NOTNULL)ENGINEInnoDBDEFAULTCHARSETutf8mb4;INSERTINTOuser(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\-eSHOW VARIABLES LIKE character%;确认以下变量均为utf8mb4character_set_servercharacter_set_databasecharacter_set_clientcharacter_set_connection再查询数据确认中文显示正常SELECT*FROMuser;小结最终在 SQL 文件首行加上SET NAMES utf8mb4;才让中文乱码问题得到了彻底、干净的解决。