我们模拟一下一条数据从插入到读取的处理流程,看看在整个流程中,字符集是如何辗转腾挪的。
【插入流程】
1. 客户端设定了自己的编码(character_set_client),接收用户的输入;
2. 客户端将用户的输入“转换”成连接的编码(character_set_connection) =====> 第一次转换
3. 客户端将转换后的数据发送给服务器; =====> 传输不会导致编码转换
4. 服务器收到客户端的数据,再判断数据列的字符集,进行字符转换 =====> 第二次转换
5. 服务器将数据存储(例如磁盘) =====> 存储不会导致编码转换
【读取流程】
略去前面的sql语句处理流程,从数据读取开始
1. 服务器从存储(例如磁盘)读取数据 =====> 存储不会导致编码转换,因此从存储读取也不需要
2. 服务器判断当前连接返回结果的字符集(character_set_results),
将读取的数据转换为结果集要求的数据 =====> 逆向的第一次转换,对应正向的第二次编码转换
3. 服务器将数据发送给客户端 =====> 传输不会导致编码转换
4. 客户端收到服务器的数据,根据客户端的字符集(character_set_client)进行编码转换 =====> 逆向第二次转换,对应正向第一次编码转换
5. 客户端显示数据 =====> 你能看到乱码的时候
有了这个流程,我们就很容易定位乱码可能产生的地方,以及产生乱码的字符集配置究竟是哪个了。
理想的情况是整个流程中,所有涉及字符转换的地方都不需要转换,这样就不会产生乱码了。
有了上面的理论分析后,我们再结合一个乱码的抓包实例,加深理解,其中有一些问题,请大家思考一下,看看是否真的理解了。
环境:
+--------------------------+-----------------------------------------------------+
| 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 |
测试语句是插入一个中文字符“你”,其utf8编码为"0xE4 0xBD 0xA0",
1. latin1发送包
思考一下1:为什么客户端和连接都设置了latin1,但最终发送的是正确的utf8编码呢?
2. latin1接收包
思考一下2:为什么接收到的还是正确的utf8编码?
3. latin1不显示乱码
思考一下3:为什么latin1显示了正确的utf8字符?
4. utf8接收包
思考一下4:为什么连接的字符集和数据库的字符集设置成一样了,接收的数据反而不是utf8了?(请与latin1接收数据包对比)
5. utf8显示包
思考一下5:为什么连接的字符集和数据库的字符集设置成一样了,显示反而乱码了?
怎么样,上面的思考题是否都有答案了,如果没有,相信下面这幅图能够帮助你:
这个抓包案例的字符变化图解:
附:mysql字符编码操作技巧
【查看字符集设置】
mysql> show variables like "%char%";+--------------------------+-----------------------------------------------------+| Variable_name| 说明|+--------------------------+-----------------------------------------------------+| character_set_client | 客户端字符集|| character_set_connection | 当前连接字符集 || character_set_database| 数据库字符集|| character_set_filesystem | 文件系统字符集,不要修改,使用binary即可|| character_set_results| 返回结果集字符集|| character_set_server | 服务器默认字符集,当数据库、表、列没有设置时, || | 默认使用此字符集|| character_set_system | 固定为utf8 |+--------------------------+-----------------------------------------------------+【修改字符集设置】