Docker创建MySQL实例的时候,如果不手动指定字符集的值,将会使用默认值,但是默认值没有统一成utf8, 有时会带来乱码问题。
基本概念
MySQL是分为服务端(Server)和客户端(Client)的。
服务端就是执行mysqld
这个文件启动服务。
客户端可以用多种,比如:Navicat, SQLyog, MySQL client命令行。
本文说的MySQL客户端指的是MySQL命令行,即执行mysql
这个文件去连接mysqld
启动起来的服务。
问题复现
创建MySQL 5.7 docker容器
docker run -p 3306:3306 --name mymysql \
-e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 \
--character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
此时不能远程连接这个MySQL Server
需要进入mysql client
mysql -u root -p
然后输入密码123456,进入client操作界面。
使用use命令选中mysql这个数据库;
> use mysql;
Database changed
执行如下命令:
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
此时就可以通过远程客户端连接这个mysql server了(先确保防火墙指定端口是开放的)。
查看此时服务器的各种编码:
mysql> show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
发现有几项并不是utf8格式的。
此时可以通过在客户端设置相应的编码暂时解决。
mysql> set character_set_client=utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | latin1 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
之所以说是暂时解决,是因为这种修改只对当前client会话有效。退出当前会话,重新与mysql server建立一个新的会话,修改就失效了。
解决方法是有的。
解决办法
可以通过创建docker mysql 实例的时候建立宿主机mysql配置文件和容器内mysql配置文件的映射。
在宿主机创建目录/opt/my_real_mysql_dir/
用于存放mysql相关的文件。
在/opt/my_real_mysql_dir/
下创建conf
目录,用于存放配置文件.
在/opt/my_real_mysql_dir/
下创建data
目录,用于存放具体数据。
在/opt/my_real_mysql_dir/conf
新建my.cnf
文件,内容如下:
[mysql]
default-character-set=utf8
[mysqld]
port=3306
skip-host-cache
skip-name-resolve
character-set-server=utf8
init_connect='SET NAMES utf8'
[client]
port=3306
default-character-set=utf8
然后按照如下方式创建mysql容器实例。
docker run -p 3306:3306 --name myrealmysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /opt/my_real_mysql_dir/conf:/etc/mysql/conf.d \
-v /opt/my_real_mysql_dir/data:/var/lib/mysql \
-d mysql:5.7
按照这种方式创建、运行mysql容器,可以最大化的自定义配置。
重新使用mysql client连接mysql server,检查其各种字符集。
mysql> show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)
都已经是utf8.
这样可以很好地规避开发过程中的MySQL乱码问题。