从发送请求到返回结果这个过程中伴随着多次字符集的转换, 在这个过程中会用到 3 个系统变量:

    系统变量 描述
    character_set_client 服务器解码请求时使用的字符集
    character_set_connection 服务器处理请求时会把请求字符串从 character_set_client 转为character_set_connection
    character_set_results 服务器向客户端返回数据时使用的字符集
    • character_set_connection 其实是服务器内部使用的字符集, 不太重要, 但是该字符集一定要 “大”

    查看:

    1. mysql> SHOW VARIABLES LIKE 'character_set_client';
    2. +----------------------+-------+
    3. | Variable_name | Value |
    4. +----------------------+-------+
    5. | character_set_client | utf8 |
    6. +----------------------+-------+
    7. 1 row in set (0.00 sec)
    8. mysql> SHOW VARIABLES LIKE 'character_set_connection';
    9. +--------------------------+-------+
    10. | Variable_name | Value |
    11. +--------------------------+-------+
    12. | character_set_connection | utf8 |
    13. +--------------------------+-------+
    14. 1 row in set (0.01 sec)
    15. mysql> SHOW VARIABLES LIKE 'character_set_results';
    16. +-----------------------+-------+
    17. | Variable_name | Value |
    18. +-----------------------+-------+
    19. | character_set_results | utf8 |
    20. +-----------------------+-------+
    21. 1 row in set (0.00 sec)

    MySQL 提供了简便的方法将它们设置为统一的字符集:

    SET NAMES 字符集名;
    
    mysql> SET NAMES utf8;
    Query OK, 0 rows affected (0.00 sec)
    

    请求从发送到结果返回过程中字符集的变化:

    1. 客户端发送请求所使用的字符集

    一般情况下客户端所使用的字符集和当前操作系统一致:

    • 类Unix系统使用的是utf8
    • Windows使用的是gbk
    1. 服务器接收到客户端发送来的请求其实是一串二进制的字节,它会认为这串字节采用的字符集是character_set_client,然后把这串字节转换为character_set_connection字符集编码的字符
    2. 因为表t的列col采用的是gbk字符集,与character_set_connection一致,所以直接到列中找字节值为0xCED2的记录,最后找到了一条记录。

      • 如果某个列使用的字符集和character_set_connection代表的字符集不一致的话,还需要进行一次字符集转换。
    3. 上一步骤找到的记录中的col列其实是一个字节串0xCED2,col列是采用gbk进行编码的,所以首先会将这个字节串使用gbk进行解码,得到字符串’我’,然后再把这个字符串使用character_set_results代表的字符集,也就是utf8进行编码,得到了新的字节串:0xE68891,然后发送给客户端。

    4. 由于客户端是用的字符集是utf8,所以可以顺利的将0xE68891解释成字符我,从而显示到我们的显示器上,所以我们人类也读懂了返回的结果。

    image.png