美文网首页
MySQL 中字符乱码问题

MySQL 中字符乱码问题

作者: djz0306 | 来源:发表于2019-07-14 09:50 被阅读0次

    编码的产生

    在计算机中只有 0 和 1, 但是在生活着有图片,视频,文字,声音等。为了把人 0 和 1 组成的数与其他内容对应起来,于是人为约定,65 —> A, 66 —> B 等。那么 0100 0001 在计算机中是 65 还是 A 这个就需要看规则了。

    从二进制编码到字符的映射就是字符集,最基础的字符集之一就是 ASCII 字符集,总共 127 个对应关系,那么 1 个字节,就够了,最高位为 0。

    但是在中文中,常用汉字就有几千个,生僻字就更多了,一个字节总共就 8 位明显不够,于是使用 2 个字节表示中文,可以有 0 到 65535 种组合,那就够用了,最早形成了 GB2312 字符集。但是,小于 127 的数,就不清楚是对应 ASCII 中的字符还是新的字符集标准了。所以 GB2312 就完全不占用 0-127,只是这样一来范围就小了很多,最终收录了 6763 个汉字,也会有一些字没有收录。

    为了解决收录不全的问题, GBK 就出来了。GBK还是双字节,他的方式是遇到的第一个字节大于 128 的就继续往后再找一个字节,最大两个字字节,然后结束本次组合,组合的结果对应一个中文。如果是第一个字节就小于 128 ,那么就直接按照 ASCII 中的映射关系。于是总共收录了汉字 21003 个,符号 883 个,提供 1894 个造字码位。

    本地编码

    GBK 基本上解决了中文的问题,但是到了其他国家,例如日本、韩国等,GBK 又不适用了。这里就引入了 ANSI,ANSI 代表本地字符集,在中文操作系统就是 GBK,在日文操作系统就是 JIS。

    国际编码

    使用本地编码 ANSI 虽然可以在各自的系统上正确显示。但是各国的文件传递,交流等又出现了新的问题。于是在解决了多字节问题以后,又出来各国的字符集兼容性问题。这种问题就可以使用 Unicode 解决。

    Unicode 是一个世界通用的码表,固定的,全世界范围的字符统一分配一个标号。所以他比较大,使用了 4 个字节,总共达到了 40 多亿,足够使用了,而常用的部分,只需要两个字节。Unicode 只负责分配编号,不负责在网络上传输,而且都是使用 4 个字节,这样就会造成浪费,还不兼容 ASCII。

    于是人们想办法简化字节,把高位浪费的 0 值,用一定的规则舍弃掉。 而最出名的转换简化方式就是 UTF。对于一个仅包含基本 7 位 ASCII 字符的 Unicode 文件,如果都是用 2 个字节的原 Unicode 编码传输,第一字节的 8 位都是 0 就造成了比较大的浪费。针对这种情况,可以使用 UTF-8 这是一种变成编码,他将基本 7 位 ASCII 字符仍然用 7位编码表示,占用一个字节,而遇到与其他 Unicode 字符混合的情况,则按照一定的算法转换,常用的字符使用 1-3 个字节编码。UTF-8 对于 Unicode 码表采用了 1-6 个不定长的字节来编码表示。Unicode 与 UTF-8 的关系就像文件与压缩文件的关系。

    但是UTF-8 的边界如何确定呢?即在 UTF-8 中取几个字节来表示映射到对应的文字、符号呢?于是按照第一个字节的高位上有几个 1 来判断需要取几个字节。例如第一个字节为:1110xxxx,则表示总共需要取 3 个字节来和 Unicode 码表来映射到字符、文字。

    如果是像 GBK 转成 UTF-8 ,那就先转成 Unicode 再转成 UTF-8

    乱码原因

    乱码的可能一般是两种可能导致的

    1. 解码时与实际编码不一致(可修复)
    2. 传输过程中,编码不一致导致字节丢失(不可修复)

    MySQL 字符集设置

    如果客户端字符集设置的是 GBK 编码,数据库服务器设置的字符集为 UTF-8。在存储和读取的过程中,必然经过一次转码的过程。中间存在一个连接器,连接客户端与服务器,客户端的字符先发给连接器,连接器选择一种编码将其转换,临时存储,再次转换成服务器需要的编码并存储在服务器。想要不乱码,就需要指定客户端的编码,让连接器不会转错、存错。往回取的时候,也需要告诉连接器,从服务端返回的时候应该转成什么格式。一共 3 个参数,连接器使用的编码,客户端发送的编码,获取的返回数据的编码。

    在客户端字符集设置的是 GBK 编码,数据库服务器设置的字符集为 UTF-8 的情况下。告诉服务器,客户端使用 GBK 编码:

    set character_set_client=gbk;
    

    告诉连接器,使用 UFT8:

    set character_set_connection=utf8; 
    

    再说明返回值使用 GBK :

    set character_set_results=gbk;
    

    通常来说,服务器的字符集要大于等于连接器,连接器的字符集要大于等于客户端。如果 client, connection, results 都相同,例如都是 GBK ,则可以直接写成 set name gbk

    UTF-8 中文截取无乱码问题

    可以查阅 UTF-8 的编码规范,如果最高位是 0xxx xxxx 就截 1 个字符,如果是 11xx xxxx 字节则截取 2 个字符,如果是 111x xxxx 字节则截取 3 个字符,依次类推。

    相关文章

      网友评论

          本文标题:MySQL 中字符乱码问题

          本文链接:https://www.haomeiwen.com/subject/qbcbkctx.html