作为LAMP的开发人员,估计或多或少都遇到过MySQL的乱码问题。就算是老鸟,有时候也会被它给郁闷。这篇文章,将从底层机制解释乱码出现的原因,并给出解决方案。(如果你只想知道,怎么解决问题,只用看完前两端就可以了)。
解决方案:
- 确定出现乱码的列(数据表中的字段)的编码,记为X
- 在你每次连接数据库的时候使用:”SET NAMES `X`”
- 确保你的写入页面和显示页面(通常是php script )有相同的编码。
比较典型的情况是:
数据库中列字段的编码是`latin1`(或者是utf8、GBK),那么在你连接数据库的地方加上”SET NAMES `latin1`” (或者是utf8、GBK)。然后保证你的写入页面add.php, list.php编码一致(比如都是GB2312、utf8)。
在这个过程中,数据库MySQL有三个重要的环境变量
- character_set_client
- character_set_connection
- character_set_result
图解:下图给出了,一个INSERT的请求可能经过怎样的编码转换,才最终被存入数据库的。
过程详细分析:
- MySQL收到客户端的一个请求“494E53455254…60E79A8460”(字符在传输过程中都是二进制编码的,这里用十六进制表示)。MySQL会按照”character_set_client“来解析这个字符串。例如“494E53455254…60E79A8460”如果按照UTF8编码解释为”INSERT …`的`”。
- MySQL内部处理会将以上的SQL字符串转码为character_set_connection。例如,如果character_set_connection等于’utf8’、’gbk’、’latin1’,以上的串将会被转码为:
utf8:494E53455254…60E79A8460
gbk:494E53455254…60B5C460
latin1:494E53455254…603F3F60 - 内部处理后(比如相关函数操作),将存入数据库之前,会将存入的数据转码为对应字段的列编码(Column Character Set)。比如列编码可能为’utf8’、’gbk’、’latin1’,那么最终存入的数据库的`的`可能是:E79A84、B5C4、3F3F。(如果存入的是3F3F,很抱歉,肯定是乱码)
参考文章:
- http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html
- 编码查询:http://orczhou.com/charset/charset.php
つづく
Leave a Reply