mysql-charset
在MySQL的使用过程中遇到的“乱码”问题,很有可能就是因为对字符集与字符序的理解不到位、设置错误造成的。
- 字符集和字符序概念
- Mysql中的字符集配置
- 一个特殊的🌰
字符集和字符序
Charset
字符集就是字符编码,常见编码有utf8 gbk gb2312 gb18030 ascii等。就是一个字符和二进制码的一个对应表。
Collation
字符序就是字符的比较,很多情况下我们不光数字会有大小比较,程序里可以直接对字符进行比较操作,字符序就定义了这个比较规则,通常使用二进制的编码比较,当然也可以定义A==a。
查看Mysql支持的字符集
1 | MySQL [charon]> SHOW CHARACTER SET; |
查看Mysql支持的字符序
1 | MySQL [charon]> SHOW COLLATION WHERE Charset = 'utf8'; |
Mysql中的编码设置
MySQL提供了不同级别的设置,包括server级、database级、table级、column级,可以提供非常精准的设置。通常情况下当不指定db的字符集字符序时,db将默认使用server的编码配置,db和table,table和column也是一样。
可以通过下面命令来查看当前db的字符集配置。
1 | MySQL [charon]> SHOW VARIABLES LIKE "%CHAR%"; |
character_set_server
就是mysql默认的字符集character_set_database
就是当前db使用字符集character_set_system
是系统元数据使用的字符集,如字段名
除此之外我们看到还有其他的一些charset配置,往往这些配置才是导致中文乱码的罪魁祸首。
SET NAMES
我们通常会使用 set names utf8;
这个命令实际上就是修改了以下3个配置。
1 | SET character_set_client = utf8; |
character_set_client
表示客户端发来语句的编码character_set_connection
表示mysqld接收到客户端语句后要转换的编码character_set_results
表示返回给客户端的数据的编码
最后还有一个character_set_filesystem
这是文件系统字符集编码,主要用于解析用于文件名称的字符串字面值,如LOAD DATA INFILE和SELECT …INTO OUTFILE等语句以及LOAD_FILE()函数.在打开文件之前,文件名称会从character_set_client转换为character_set_filesystem指定的编码. 实际中很少用到
解决中文乱码问题
统一UTF8
最简单的方式是统一所有的编码设置为utf8。这里需要注意的是如果使用终端进行查询的话,还需要设置终端使用的文件编码,通过locale可以来查看。通常设置成zh_CH.utf8。具体的设置可以自行百度locale。
非utf8编码数据
但有时候一些历史的项目使用了其他的编码方式,这个时候乱码问题就需要随机应变来解决了。
比较特殊的一个编码方式是CHARSET=latin1;
Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。
ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。
因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。
所以理论上latin1字符集可以存各种编码,重要的是你需要知道当时写入的是何种编码。当读取出来以后,如果在终端下,就会理解成locale类型(如果locale系gbk,当时写入的gbk中文串可正常回显)。
此外还有另外一种方法就是使用mysql的内置函数去进行编码的修改convert(unhex(hex(convert(server_name using latin1))) using gb2312)
也可以解决乱码问题。