转载

mysql字符转化以及乱码原因

mysql中存入数据时发生的编码转换过程:
1、在终端(Terminal,可以是bash窗口,也可以是客户端工具如navicat)中输入,输入的内容由Terminal根据其自己的字符进行编码。
2、经Terminal编码后的二进制流被传输到mysql server。mysql server(mysql engine)根据参数character_set_client的字符设置来对该二进制流进行解码。
3、解码之后,mysql server再次根据目的表,即table的字符集来判断是否需要字符编码转换。如果character_set_client的字符设置和table定义时的character设置一致,则无需字符编码转换。否则进行转换,然后将转换后的二进制流存放到数据文件(file)中去。
总结:client ------> server(engine) -----> file     需要经过三次编码,两次编码转化。

mysql中取出数据时发生的编码转换过程:
1、从数据文件(file)中读出二进制数据流,将该数据流根据table定义时的character设置来进行解码。
2、在用table character对二级制数据流进行解码之后,在mysql engine(mysql server)中,需要根据参数character_set_client的字符集设置对解码后的数据库流再一次进行编码,将编码之后的二级制数据库流传输到client端。
3、client端,即终端(Terminal)根据其自己的字符集编码来展示查询结果。
总结:  file ------> server(engine) -----> client  需要经过三次编码,两次编码转化。

可能会有些疑问,在上面的分析中,数据都是以二进制流的方式在各个节点之间流动的。那么为什么需要编码转化了?
1、client 和 server(engine) 之间的转换,或者说编解码是为了对传进来的二进制流做语法和词法解析,否则你不会知道传进来的是insert还是update。
2、file 和 server(engine) 之间的转换是为了在从数据文件读入数据后,在存储引擎内部进行字符级别的操作。

经过以上分析,应该很快发现导致乱码出现的原因是有以下几种:
1、数据在存入的时候和取出的时候,编码不一致。比如存入时用的utf8,取出时用的GBK。
2、编码转换不是无损编码转换导致乱码出现。比如clien是utf8,mysql server中的character_set_client设置为gbk,表结构的字符集设置为utf8。这里会有两次编码转化,client到server时,utf8要转为gbk,然后server到file时,gbk要转为utf8。由于gbk到utf8是有损编码转化,导致了乱码出现。

无损编码转换:假设我们要把用编码A表示的字符X,转化为编码B的表示形式,而编码B的字形集中并没有X这个字符,那么此时我们就称这个转换是有损的。
但不是任何两种字符集编码之间的转换都是有损,转换是否有损取决于以下几点:
------被转换的字符是否同时在两个字符集中
------标字符集是否能够对不支持字符,保留其原有表达形式。(比如latin1在遇到自己无法表示的字符时,会保留原字符集的编码数据,并跳过忽略该字符进而处理后面的数据。)

因此只要客户端,MySQL Server的character-set-client,table charset的三个字符集完全一致就可以保证一定不会有乱码出现了。
正文到此结束
Loading...