全文内容概述
- 字符集是什么?有哪些常见的字符集?字符集的发展和历史知识
- Unicode字符集的由来和特点
- MYSQL数据库中的字符集、字符集排序规则、编码方式
- 与数据库中字符相关的问题
概念篇
什么是字符集(Characters Set)
我先说一下我看了这么多字符集相关的知识和内容,之后的一个结论。字符集归根到底其实就是一个很简单的哈希表映射,追根溯源就是和我们平时工作中开发最常见的一个东西。哈希表,它实际上就是映射一个我们看到的字符和一个数字码值的映射集合。字符集告诉了计算器,什么是"1","你","&",然后显示器将它映射成这些我们看到的内容并展示给大家。
原来我们天天接触的字符集,我们看到的语言就是很简单的一个数据结构嘛。哈希表,一一映射。没什么难懂的,当我知道了它底层的存储结构之后,就再也不慌啦。
摘自百度百科
字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,就需要进行字符编码,以便计算机能够识别和存储各种文字。中文文字数目大,而且还分为简体中文和繁体中文两种不同书写规则的文字,而计算机最初是按英语单字节字符设计的,因此,对中文字符进行编码,是中文信息交流的技术基础。
常见的字符集有哪些
- ASCII
ASCII(American Standard Code for Information Interchange,美国信息互换标准编码)是基于罗马字母表的一套电脑编码系统。它主要用于显示现代英语和其他西欧语言。它是最通用的单字节编码系统,并等同于国际标准ISO 646。控制字符:回车键、退格、换行键等。可显示字符:英文大小写字符、阿拉伯数字和西文符号。7位编码的字符集只能支持128个字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。ASCII扩展字符集:它是从ASCII字符集扩充出来的,扩充后的符号增加了表格符号、计算符号、希腊字母和特殊的拉丁符号。
特点
7位(bits)表示一个字符,共128字符,字符值从0到127,其中32到126是可打印字符。
存储大小:单字节的字符集
- GB2312
GB2312又称为GB2312-80字符集,全称为《信息交换用汉字编码字符集·基本集》,由原中国国家标准总局发布,1981年5月1日实施。
GB2312是中国国家标准的简体中文字符集。它所收录的汉字已经覆盖99.75%的使用频率,基本满足了汉字的计算机处理需要。在中国大陆和新加坡获广泛使用。
GB2312收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共 7445 个图形字符。其中包括6763个汉字,其中一级汉字3755个,二级汉字3008个;包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。
特点
GB2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
各区包含的字符如下:01-09区为特殊符号;16-55区为一级汉字,按拼音排序;56-87区为二级汉字,按部首/笔画排序;10-15区及88-94区则未有编码。
双字节表示
两个字节中前面的字节为第一字节,后面的字节为第二字节。习惯上称第一字节为“高字节” ,而称第二字节为“低字节”。
“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上0xA0)。
编码举例
以GB2312字符集的第一个汉字“啊”字为例,它的区号16,位号01,则区位码是1601,在大多数计算机程序中,高字节和低字节分别加0xA0得到程序的字处理编码0xB0A1。计算公式是:0xB0=0xA0+16, 0xA1=0xA0+1。
- BIG5
又称大五码或五大码,1984年由台湾财团法人信息工业策进会和五家软件公司宏碁 (Acer)、神通 (MiTAC)、佳佳、零壹 (Zero One)、大众 (FIC)创立,故称大五码。
Big5码的产生,是因为当时台湾不同厂商各自推出不同的编码,如倚天码、IBM PS55、王安码等,彼此不能兼容;另一方面,台湾政府当时尚未推出官方的汉字编码,而中国大陆的GB2312编码亦未有收录繁体中文字。
Big5字符集共收录13,053个中文字,该字符集在中国台湾使用。耐人寻味的是该字符集重复地收录了两个相同的字:“兀”(0xA461及0xC94A)、“嗀”(0xDCD1及0xDDFC)。
特点
Big5码使用了双字节储存方法,以两个字节来编码一个字。第一个字节称为“高位字节”,第二个字节称为“低位字节”。高位字节的编码范围0xA1-0xF9,低位字节的编码范围0x40-0x7E及0xA1-0xFE。
各编码范围对应的字符类型如下:0xA140-0xA3BF为标点符号、希腊字母及特殊符号,另外于0xA259-0xA261,存放了双音节度量衡单位用字:兙兛兞兝兡兣嗧瓩糎;0xA440-0xC67E为常用汉字,先按笔划再按部首排序;0xC940-0xF9D5为次常用汉字,亦是先按笔划再按部首排序。
局限性
尽管Big5码内包含一万多个字符,但是没有考虑社会上流通的人名、地名用字、方言用字、化学及生物科等用字,没有包含日文平假名及片假名字母。例如台湾视“着”为“著”的异体字,故没有收录“着”字。康熙字典中的一些部首用字(如“亠”、“疒”、“辵”、“癶”等)、常见的人名用字(如“堃”、“煊”、“栢”、“喆”等) 也没有收录到Big5之中
- GB18030
GB18030的全称是GB18030-2000《信息交换用汉字编码字符集基本集的扩充》,是我国政府于2000年3月17日发布的汉字编码国家标准,2001年8月31日后在中国市场上发布的软件必须符合本标准。GB 18030字符集标准的出台经过广泛参与和论证,来自国内外知名信息技术行业的公司,信息产业部和原国家质量技术监督局联合实施。
GB 18030字符集标准解决汉字、日文假名、朝鲜语和中国少数民族文字组成的大字符集计算机编码问题。该标准的字符总编码空间超过150万个编码位,收录了27484个汉字,覆盖中文、日文、朝鲜语和中国少数民族文字。满足中国大陆、香港、台湾、日本和韩国等东亚地区信息交换多文种、大字量、多用途、统一编码格式的要求。并且与Unicode 3.0版本兼容,填补Unicode扩展字符字汇“统一汉字扩展A”的内容。并且与以前的国家字符编码标准(GB2312,GB13000.1)兼容。
特点
GB 18030标准采用单字节、双字节和四字节三种方式对字符编码。单字节部分使用0×00至0×7F码(对应于ASCII码的相应码)。双字节部分,首字节码从0×81至0×FE,尾字节码位分别是0×40至0×7E和0×80至0×FE。四字节部分采用GB/T 11383未采用的0×30到0×39作为对双字节编码扩充的后缀,这样扩充的四字节编码,其范围为0×81308130到0×FE39FE39。其中第一、三个字节编码码位均为0×81至0×FE,第二、四个字节编码码位均为0×30至0×39。
双字节部分收录内容主要包括GB13000.1全部CJK汉字20902个、有关标点符号、表意文字描述符13个、增补的汉字和部首/构件80个、双字节编码的欧元符号等。 四字节部分收录了上述双字节字符之外的,包括CJK统一汉字扩充A在内的GB 13000.1中的全部字符。
- Unicode
千呼万唤始出来,终于和我们的大BOSS,也是我们基本上不管少数特殊情况都一定会使用和遇见的Unicode字符集。
Unicode字符集从1990年代诞生以来就一直在不断地更新和扩充,一开始是16个比特的标识空间。从Unicode2.0开始就转变成可以表示U+0000~U+10FFFF的21个比特标识空间的字符集。到目前最新的版本是13.0。
Version 13.0 (2020)
Code Point Type | Count | Delta |
---|---|---|
Total Designated | 283,506 | 5,930 |
Reserved Code Points | 830,606 | -5,930 |
最新的版本已经标识了28万多个字符,还有83万个码值可以继续使用。
Characters Before Unicode
Fundamentally, computers just deal with numbers. They store letters and other characters by assigning a number for each one. Before Unicode was invented, there were hundreds of different systems, called character encodings, for assigning these numbers. These early character encodings were limited and could not contain enough characters to cover all the world's languages. Even for a single language like English no single encoding was adequate for all the letters, punctuation, and technical symbols in common use.
Early character encodings also conflicted with one another. That is, two encodings could use the same number for two different characters, or use different numbers for the same character. Any given computer (especially servers) would need to support many different encodings. However, when data is passed through different computers or between different encodings, that data runs the risk of corruption.
我们都知道,计算机只会处理数字。在没有Unicode字符集之前,各个国家和系统之间都有自己的定义的字符集还有编码规则,这导致出现了一些问题,比如有的字符集表示的空间不够,不能很好的囊括足够的字符。每一个电脑为了能够很好的展示和表达这些字符,需要支持很多不同的编码方式,当数据在两种不同的字符编码规则之间进行存储和传输的时候,数据冲突的风险大大的提高了。
有了Unicode字符集之后,一切都变的更加统一和规范了。
它为全世界的语言、字符和各种符号提供了唯一的码值,无论你是什么平台、什么国家、什么系统。它可以适应目前现代的所有数据存储和传输,并且不发生数据冲突。也支持WWW互联网的字符和元素,使用了Unicode字符集就可以不用再去考虑太多的关于字符冲突、数据存储、数据传输等问题。想表达的字符,这里都有。而且大部分的交互平台和系统也支持Unicode字符集。算是为计算机和人类语言的沟通做出了很大的贡献。
最后用一个表格总结一下,上面常见字符集的特点对比。
概念 | 表示空间大小 | 编码规则 | 局限性 | 推荐指数 | |
---|---|---|---|---|---|
ASCII | 单字节 | 只能支持128个字符 | 四星 | ||
GB2312 | 双字节 | 支持的中文汉字还不够全面,同时不能很好的处理和东南亚周边国家的数据兼容 | 三星 | ||
BIG5 | 双字节 | 有部分汉字没有收录,同时会有歧义字 | 三星 | ||
GB18030 | 字节、双字节和四字节三种方式 | 主要支持的是东南亚国家和地区语言,对全球的语言兼容性还有欠缺 | 四星 | ||
Unicode | 21 bits | UTF8,UTF16,UTF32,UCS2等 | 无 | 五星 |
无脑用Unicode就好了
MYSQL数据库中的字符集、字符集排序规则
MYSQL中的字符集
MySQL字符集总览
MySQL中支持的字符集,可以通过一下命令去查看。
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
...
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 |
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |
...
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
...
| binary | Binary pseudo charset | binary | 1 |
...
这里特别要注意的一点就是utf8字符集,因为MySQL自身的缘故。utf8实际上是只有最大三个字节表示的字符集,也叫做utf8mb3。它和国际标准的utf8不一样。所以这也是为什么,数据库实践中要使用utf8mb4的缘故,就是为了支持除了BMP以外的更多拓展字符。
字符集转换
MySQL和字符相关的数据类型有两种,一种是二进制字符串类型(Binary data type) 另一种是非二进制字符串类型(NonBinary data type)。
使用binary data type 一定要记得只能存储一种字符集的二进制编码。不要存储多种。否则MySQL无法正确的进行数据转换
转换规则:
- 如果是二进制字符串类型,可以直接转成对应非二进制字符串类型。比如一个VARBINARY 列存储了utf8mb4的二进制字符串,直接使用alter 语句进行转换。
ALTER TABLE t MODIFY col1 VARCHAR(50) CHARACTER SET utf8mb4;
就可以正常转换了。
- 如果是两个二进制字符串进行转换,那些不存在于两个字符集中的数据可能出现数据丢失的情况。这里我举一个可以正常转换的例子和一个不能正常转换的例子。
请看下面的语句执行:
#创建一个big5的字符集的表
CREATE TABLE `table_with_big5` (
`column1` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=big5
#往里面插入一点数据
INSERT into table_with_big5 values('你好');
#1.查看此时的数据和对应的底层存储数据
SELECT column1,HEX(column1) from table_with_big5;
#2.这个时候我们做一下字符集转换
ALTER table table_with_big5 CONVERT to CHARSET utf8mb4;
#3.然后我们再看一下数据和对应的底层存储数据
SELECT column1,HEX(column1) from table_with_big5;
#4.这个时候我们插入一个表情,这个是utf8mb4才支持,而big5并不支持的字符
INSERT into table_with_big5 values('😂');
#5.再次转换字符集变回big5
ALTER table table_with_big5 CONVERT to CHARSET big5;
1处的查询结果如下,正常的显示big5的数据和二进制数据。
2处的查询结果如下,底层的二进制数据已经发生了变化。变成了utf8mb4的编码规则了。并且也正常的显示了中文"你好"
因为"你好"这个中文字符在两个字符集都存在,所以可以正常转换。转换的过程应该是big5字符集的"你好"->在utf8mb4的字符集中去查找对应的中文字符->然后映射到utf8mb4的字符集码值->按照编码规则编码后存储回数据库。
5处的转换结果,发生了报错。表情符合在big5中并不存在。所以发生了转换异常。
在官方手册中也不推荐直接转成整个表的字符集,因为这个可能发生因字符集不同所需的存储空间不同,导致存储数据丢失或者无法转换的情况。比如一个varchar(100)的数据类型是可以存储100个字符的,如果从Latin字符集转成utf8字符集,latin是一个字符一个字节。而utf8的一个字符由1-3个字节组成。那么100个字节的latin字符集可以存储100个字符,在utf8这里最多就只能存储30多个字符了。数据信息缩小了不少。
一种方法是先将数据类型转大,然后再换个字符集。
MYSQL中的字符集排序规则(Character set Collations)
collation就是MySQL数据库中数据进行比较和排序的规则依据,当你要对两个字符串数据进行比较的时候。用的就是collation的规则,<u>它和数据本身无关。数据本身的存储只和字符集以及编码规则有关</u>,所以当你再面对是否collation的改变是否会对数据产生影响的时候,你可以很确认的告诉自己。没影响!
collation的命名规则是:字符集______规则______类型
第一部分是字符集,代表的是这个排序规则是在什么字符集下的排序。比如常见的有,utf8mb3(以后在下文中,关于MYSQL场景下谈到的utf8就是等价于utf8mb3而不是国际标准Unicode的utf8,这个后面会有解释),utf8mb4,ascii等
第二部分是具体规则,代表的是不同语言和国家自己定义的排序规则的标准。比如有Unicode、general、unicode_520、swedish
第三部分是类型,目前有如下表格的排序类型
Suffix | Meaning |
---|---|
_ai |
Accent-insensitive |
_as |
Accent-sensitive |
_ci |
Case-insensitive |
_cs |
Case-sensitive |
_bin |
Binary |
通过英文释义都很好理解,就是是否对大小写敏感、对声调敏感等。
综合起来就是我们在实际MySQL数据库中可以看到的,latin1_swedish_ci、latin1_german1_ci、utf8mb4_unicode_ci、utf8mb4_general_ci等collation值了。
一个字符集可能有多个排序规则collation,而每一个collation对应唯一一个字符集。即为它命名规则的第一部分。
特性
就是不同的字符集是不能有同样的排序规则的
每一个字符集有一个默认的排序规则,可以通过查询特定的语句获得MYSQL的配置说明
每一个字符集会有多种排序规则,为了选择合适的排序规则。可以先对自己的应用数据做基准实验测试来得到你想要的结果
collation在数据库中的表现
上面讲了很多概念,下面我们直接在数据库中进行实际操作,来看看collation的影响表现是怎么样的。
1.首先创建一个latin1_general_cs的表,并往里面插入几条数据
CREATE TABLE table_with_cs_collation(
id BIGINT UNSIGNED not null auto_increment COMMENT 'id',
column_1 VARCHAR(100) not null DEFAULT '' COMMENT 'column 1',
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs COMMENT='latin1_general_cs table';
INSERT into table_with_cs_collation(column_1) VALUES('ab');
INSERT into table_with_cs_collation(column_1) VALUES('aB');
INSERT into table_with_cs_collation(column_1) VALUES('Ab');
INSERT into table_with_cs_collation(column_1) VALUES('AB');
排序语句操作
SELECT * from table_with_cs_collation ORDER BY column_1 ASC
结果如下
查询语句操作
SELECT * from table_with_cs_collation WHERE column_1 like '%A%'
结果如下
2.创建一个latin1_general_ci的表,并往里面插入几条数据
CREATE TABLE table_with_latin1_general_ci(
id BIGINT UNSIGNED not null auto_increment COMMENT 'id',
column_1 VARCHAR(100) not null DEFAULT '' COMMENT 'column 1',
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci COMMENT='latin1_general_ci table';
INSERT into table_with_latin1_general_ci(column_1) VALUES('ab');
INSERT into table_with_latin1_general_ci(column_1) VALUES('aB');
INSERT into table_with_latin1_general_ci(column_1) VALUES('Ab');
INSERT into table_with_latin1_general_ci(column_1) VALUES('AB');
排序语句操作
SELECT * from table_with_latin1_general_ci ORDER BY column_1 ASC
结果如下
查询语句
SELECT * from table_with_latin1_general_ci WHERE column_1 like '%A%'
结果如下
从实践的结果我们可以看出,ci和cs的区别,在排序上。cs区分大小写,严格的按照了ASCII的字符集的符号的code point顺序返回结果。ci则把a排在了前面。并没有按照字符集的code point顺序。
在查询语句的结果也可以看到,区分大小写的cs在查询A的时候没有返回a的结果,在不区分大小写的ci上则返回了。
The binary Collation Compared to _bin Collations
前面我们讨论的都是非二进制字符串的collation,二进制数据类型其实不在我常用的数据类型范围内。一般情况下,我们使用的都是非二进制的字符串类型。比如varchar char text等数据类型。
二进制字符串和非二进制字符串的比较的区别主要体现在以下几个方面
- 比较的基本单元
- 字符集转换
- 字母大小写转换
- comparison时对待末尾空格的处理
- 插入和查询时对待末尾空格的处理
具体的区别可以直接查看官网的手册,这里就不再过多描述了。The binary Collation Compared to _bin Collations
常见问题解答
为什么MYSQL数据库千万不用要utf8字符集?
答:因为MySQL中utf8字符集 是utf8mb3的字符集,它和国际Unicode标准字符集不太一样。它最大使用了3个字节去表示字符。国际标准的UTF-8使用最大四个字节去表示表示字符。所以我们经常会遇到类似于表情😭之类的字符无法存储报错的情况。这种情况就是使用utf8字符集导致的。所以推荐是使用utf8mb4,可以保持和国际UTF-8一样的表示范围。
Binary data type 和Nonbinary data type 在存储上有区别吗?
两者在底层都是二进制字节存储,从本质上来讲并无差异。但是Nonbinary数据类型时会带上字符集的信息,也就是说它的二进制字节是符合它定义的字符集的规律的。可以被此字符集通过规则进行解码并表现出对应字符。而binary数据类型则比较存粹就是二进制字节。