MySQL乱码之客户端字符集

环境

  • Red Hat Enterprise Linux Server release 7.4 (Maipo)
  • MySQL 5.7.22

现象

查表的时候显示某个字段乱码

# mysql -u -p -S /tmp/mysql.sock
mysql> select * from my_a limit 1\G
*************************** 1. row ***************************
         id: 2
 gmt_create: 2019-01-01 00:00:02
 gmt_modify: 2019-03-03 21:12:36
gmt_create1: 2019-03-03 21:12:36
gmt_modify1: 2019-03-03 21:12:36
          k: 279134
          c: 50739423477-59896895752-91121550334-25071371310-03454727381-25307272676-12883025003-48844794346-97662793974-67443907837
        pad: 10824941535-62754685647-36430831520-45812593797-70371571680
          d: 279134
          e: 50739423477-59896895752-91121550334-25071371310-03454727381-25307272676-12883025003-48844794346-97662793974-67443907837
       pad2: ???????
??????????
1 row in set (0.00 sec)

查看当前session字符集设置

mysql> show variables like '%chara%';
+--------------------------+-------------------------------------------------------------------------+
| Variable_name | Value |
+--------------------------+-------------------------------------------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /home/mysql/program/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+-------------------------------------------------------------------------+
8 rows in set (0.00 sec)

解决

方法1

修改当前session的字符集设置,再查看表记录

mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%chara%';
+--------------------------+-------------------------------------------------------------------------+
| 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 | /home/mysql/program/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+-------------------------------------------------------------------------+
8 rows in set (0.00 sec)

mysql> select * from my_a limit 1\G
*************************** 1. row ***************************
         id: 2
 gmt_create: 2019-01-01 00:00:02
 gmt_modify: 2019-03-03 21:12:36
gmt_create1: 2019-03-03 21:12:36
gmt_modify1: 2019-03-03 21:12:36
          k: 279134
          c: 50739423477-59896895752-91121550334-25071371310-03454727381-25307272676-12883025003-48844794346-97662793974-67443907837
        pad: 10824941535-62754685647-36430831520-45812593797-70371571680
          d: 279134
          e: 50739423477-59896895752-91121550334-25071371310-03454727381-25307272676-12883025003-48844794346-97662793974-67443907837
       pad2: 你知道不???
???你这是在干嘛?
1 row in set (0.00 sec)

方法2

在客户端mysql命令行参数加上–default-character-set=utf8

mysql -u -p -S /tmp/mysql.sock --default-character-set=utf8

方法3

在mysql配置文件中加上如下内容,并在客户端mysql命令行参数加上–defaults-file=/home/mysql/conf/my1.cnf

[mysql]
default-character-set = utf8

/// mysql命令行参数
# mysql --defaults-file=/home/mysql/conf/my1.cnf -u -p

疑问

如果在mysql配置文件里的[mysql]下加了default-character-set = utf8,但如果使用mysql -u -p -S /tmp/mysql.sock不指定配置文件去连接mysql,此时显示的character_set_client、character_set_connection、character_set_results仍是latin1,那么此时的客户端mysql命令是从哪里去获取这些字符集的值的呢?

使用strace来看一下mysql命令行连接的时候的情况:

# strace -o /tmp/bbb_my.strace mysql -u -p -S /tmp/mysql.sock

查看后发现读的最后的配置文件是/etc/my.cnf.d/mysql-clients.cnf
在这里插入图片描述
查看/etc/my.cnf和/etc/my.cnf.d/mysql-clients.cnf中的内容

/etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

/etc/my.cnf.d/mysql-clients.cnf
#
# These groups are read by MariaDB command-line tools
# Use it for options that affect only one utility
#

[mysql]

[mysql_upgrade]

[mysqladmin]

[mysqlbinlog]

[mysqlcheck]

[mysqldump]

[mysqlimport]

[mysqlshow]

[mysqlslap]

发现配置文件中没有相应的字符集设置,所以采用的是默认的character_set_client、character_set_connection、character_set_results的字符集。默认的字符集是latin1,参考官网:

The mysql, mysqladmin, mysqlcheck, mysqlimport, and mysqlshow client programs determine the default character set to use as follows:

  • In the absence of other information, each client uses the compiled-in default character set, usually latin1.

我们在/etc/my.cnf.d/mysql-clients.cnf文件中的[mysql]下添加default-character-set = utf8,保存后,再通过mysql -u -p -S /tmp/mysql.sock去连接,发现如下,character_set_client、character_set_connection、character_set_results已被修改为utf8。


mysql> show variables like '%chara%';

+--------------------------+-------------------------------------------------------------------------+

| 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 | /home/mysql/program/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |

+--------------------------+-------------------------------------------------------------------------+

8 rows in set (0.01 sec)

更进一步

其实在官网中除了上面提到的一点,还有另一点,完整的如下:

The mysql, mysqladmin, mysqlcheck, mysqlimport, and mysqlshow client programs determine the default character set to use as follows:

  • In the absence of other information, each client uses the compiled-in default character set, usually latin1.

  • Each client can autodetect which character set to use based on the operating system setting, such as the value of the LANG or LC_ALL locale environment variable on Unix systems or the code page setting on Windows systems. For systems on which the locale is available from the OS, the client uses it to set the default character set rather than using the compiled-in default. For example, setting LANG to ru_RU.KOI8-R causes the koi8r character set to be used. Thus, users can configure the locale in their environment for use by MySQL clients.

The OS character set is mapped to the closest MySQL character set if there is no exact match. If the client does not support the matching character set, it uses the compiled-in default. For example, ucs2 is not supported as a connection character set, so it maps to the compiled-in default.

也就是说mysql client会自动去识别client端os的字符集设置,比如:LANG、LC_ALL。如果locale对于os是可用的,那么mysql client就会把它作为默认的字符集,而不是使用内建的字符集。

查看系统的locale设置:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

进入mysql查看此时字符集

$ mysql -S /tmp/mysql.sock
mysql> show variables like '%char%';
+--------------------------+----------------------------------+
| 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/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.00 sec)

修改系统的locale设置

$ export LANG='zh_CN.GBK'
$ locale
LANG=zh_CN.GBK
LC_CTYPE="zh_CN.GBK"
LC_NUMERIC="zh_CN.GBK"
LC_TIME="zh_CN.GBK"
LC_COLLATE="zh_CN.GBK"
LC_MONETARY="zh_CN.GBK"
LC_MESSAGES="zh_CN.GBK"
LC_PAPER="zh_CN.GBK"
LC_NAME="zh_CN.GBK"
LC_ADDRESS="zh_CN.GBK"
LC_TELEPHONE="zh_CN.GBK"
LC_MEASUREMENT="zh_CN.GBK"
LC_IDENTIFICATION="zh_CN.GBK"
LC_ALL=

查看此时mysql client的字符集

$ mysql -S /tmp/mysql.sock
mysql> show variables like '%char%';
+--------------------------+----------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------+
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.01 sec)

如果LC_CTYPE与其余参数的设置不一致,则以LC_CTYPE为准

$ locale
LANG=zh_CN.GBK
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="zh_CN.GBK"
LC_TIME="zh_CN.GBK"
LC_COLLATE="zh_CN.GBK"
LC_MONETARY="zh_CN.GBK"
LC_MESSAGES="zh_CN.GBK"
LC_PAPER="zh_CN.GBK"
LC_NAME="zh_CN.GBK"
LC_ADDRESS="zh_CN.GBK"
LC_TELEPHONE="zh_CN.GBK"
LC_MEASUREMENT="zh_CN.GBK"
LC_IDENTIFICATION="zh_CN.GBK"
LC_ALL=

mysql> show variables like '%char%';
+--------------------------+-------------------------------------------------------------------------+
| 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 | /home/mysql/program/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+-------------------------------------------------------------------------+
8 rows in set (0.00 sec)

注意:如果locale和疑问一节中mysql client会读取的/etc/my.cnf.d/mysql-clients.cnf配置文件[mysql]都配置了,且不一致的话,则以mysql client会读取的配置文件为准。

引申

如果locale显示有问题,如下。是因为系统压根就没有UTF-8这个语系,所以会报找不到。可以通过locale -a查看系统支持的语系。在这种情况下,mysql client就继承不了LC_CTYPE的character set,需要将LC_CTYPE修改成正确的值。

# locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.UTF-8
LC_CTYPE=UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
# mysql -S /tmp/mysql.sock
mysql> show variables like '%char%';
+--------------------------+-------------------------------------------------------------------------+
| Variable_name | Value |
+--------------------------+-------------------------------------------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /home/mysql/program/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+-------------------------------------------------------------------------+
8 rows in set (0.00 sec)

总结

通过这篇文章,我们可以知道mysql client去连接mysql server的时候,关于character set的值是从哪几个地方去获取的

  • set names utf8修改字符集
  • 命令行接–default-character-set=utf8参数
  • 命令行接配置文件,配置文件[mysql]下配置default-character-set=utf8
  • 命令行不接配置文件,客户端默认读取的配置文件/etc/my.cnf.d/mysql-clients.cnf中[mysql]下添加default-character-set=utf8
  • locale的配置

这里,character_set_database、character_set_filesystem、character_set_server、character_set_system的含义不加赘述,可以参考官网。

参考

https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html

https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_character_set_client

https://www.cnblogs.com/JMLiu/p/8313204.html

http://www.mamicode.com/info-detail-1866747.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值