{{ it.name }}
{{ it.text }}
1、字符集
ASCII 是最基础的字符集,每个 ASCII 字符占用1字节,ASCII 仅利用了8位编码能力的一半,最高位恒为 0 。
Latin1 字符集利用剩下的一半编码了西欧常用字母。
UCS-2 使用2字节编码,容量为65536 。
UTF-16 在这基础上, 增加了临时使用2个2字节,编码特殊字符的能力。
UTF-32 使用定长4字节编码。
GB系列、UTF-8 等字符集,0~127编码和 ASCII 一样,使用单字节。在最高位不为0时,额外使用1~3字节编码。
即它们是变长编码,每个字符占用1~4字节
只表达 ASCII 0~127字符的话,Latin1、GB系列、UTF8 等编码是完全相同的. 而 UTF16 和 UTF32 则会有额外的空白。
使用如下 SQL 语句可以看到当前 MySQL 实例支持的字符集(和 collation )。
题外:什么是 collation
MySQL文档
MySQL文档( https: v.mysql.com/doc/refman/8.0/en/adding-collation.html):collation 是进行字符串比较或排序时使用的规则。例如:
大小写是否敏感(case sensitive / insensitive)特殊的相等规则: ij = ij
2、MySQL 系列参数
执行 SQL show variables like 'character%' 可以获得 MySQL 中关于字符集的几个参数。
2.1 参数 character_set_clientcharacter_set_client 并不是客户端使用的字符集。
用户输入什么数据,客户端就发送什么数据。字符集由用户输入决定。
character_set_client 是服务端的参数。
服务端认为客户端发来的数据是以 character_set_client 编码的。
character_set_client不能被设置为以下几个字符集 (参考链接:https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-impermissible-client-charset)
3、一个乱码原因的勘误
mysql> select * from ytt_new10.t2;
a1
事实上,MySQL 知道character_set_client = gb2312,也知道t1表编码为 utf8 。写入过程中,MySQL 会进行转换,不应当发生乱码。
发生乱码的真正原因是:我们发送给 MySQL 的数据 ,并不是以 gb2312 编码的。是我们欺骗了 MySQL 。
insert ... "("病毒滚吧!")这个语句, 是以终端字符集 utf8 编码的. MySQL 把 utf8 数据当作 gb2312 数据, 转换成 utf8 数据, 自然产生了乱码。
让我们以 gb2312 发送数据:
# 终端编码为UTF-8. 使用iconv转换文件编码.
$ echo 'insert into ytt_new10.t1 val("病毒滚吧!");' | iconv -f utf8 -t gb2312 > insert-gb.txt
$ cat insert-gb.txt # 终端无法正常显示GB2312字符
insert into t1 val("???????ɣ?");
$ mysql -h ... --default-character-set=gb2312 < insert-gbk.txt
SELECT 时,MySQL 会把数据转换成character_set_results再返回给客户端。终端可能不支持非 UTF8 字符的显示,需要转换。
$ mysql ... --default-character-set=utf8 -e 'select * from ytt_new10.t1'
病毒滚吧!
$ mysql ... --default-character-set=gb2312 -e 'select...' | iconv -f gb2312 -t utf8
病毒滚吧!
4、字符集 client 到 connection 转换的意义
收到客户端发来的语句后, 服务端会将语句从 character_set_client 转换为 character_set_connection
这个步骤乍一看多此一举
直接以client字符集执行,MySQL 也会正常转换到表字符集。也可以让客户端直接以connection字符集发送语句。那么,为什么不将两个参数合并呢?搜索发现,使用转换层的潜在原因如下:不同字符集的某些行为是完全不同的:mysql> set character_set_connection = 'utf8';
mysql> select length("hello");
| 5 |
mysql> set character_set_connection = 'utf32';
mysql> select length("hello");
| 20 |
由于character_set_client的限制,客户端不能直接以 UTF32 等字符集发送语句。如果我们就是想要 UTF32 下的行为(函数结果、排序规则等),就需要由 MySQL 进行一层转换。