MySQL字符集和比较规则

MySQL字符集和比较规则

字符集和比较规则简介

字符集: 描述字符与二进制数据的映射关系

比较规则:比较指定字符集中的字符的规则

字符集

我们知道,计算机无法直接存储字符串,实际存储的都是二进制数据。字符集是有限的,也就是字符范围,比如ASCII字符集包含了128个字符与进制数据的映射关系将字符根据编码规则映射成二进制数据的过程叫做编码,将二进制数据根据编码规则映射到字符的过程叫做解码

举个例子,在ASCII字符集中,存在如下映射关系:

'A' -> 01000001(十六进制为0x41)
'B' -> 01000010(十六进制为0x42)
'a' -> 01100001(十六进制为0x61)
'b' -> 01100010(十六进制为0x62)
'我' -> 不存在,因为ASCII字符集的字符范围里并不存在'我'8位组的对应关系
查看字符集

命令:SHOW (CHARSET | CHARACTER SET) [LIKE 匹配的模式]

mysql> SHOW CHARSET;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
...
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| utf8mb3  | UTF-8 Unicode                   | utf8mb3_general_ci  |      3 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_0900_ai_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.01 sec)

本文使用的MySQL8.0版本中共支持41中字符集(仅列出了常用字符集)。其中Default collation为该字符集默认的比较规则,Maxlen是最多需要使用几个字节来映射一个字符。

比较规则

在确定字符集之后,还需要比较字符集中两个字符的大小或是否相等,此时,就需要用到字符集的比较规则。最简单的比较规则就是:直接比较两个字符对应的二进制编码的大小。一个字符集可以有多种比较规则。

查看比较规则

命令:SHOW COLLATION [LIKE 匹配的模式]

mysql> SHOW COLLATION LIKE '%utf8mb4%';
+----------------------------+---------+-----+---------+----------+---------+---------------+
| Collation                  | Charset | Id  | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+---------+-----+---------+----------+---------+---------------+
| utf8mb4_0900_ai_ci         | utf8mb4 | 255 | Yes     | Yes      |       0 | NO PAD        |
| utf8mb4_0900_as_ci         | utf8mb4 | 305 |         | Yes      |       0 | NO PAD        |
| utf8mb4_0900_as_cs         | utf8mb4 | 278 |         | Yes      |       0 | NO PAD        |
| utf8mb4_0900_bin           | utf8mb4 | 309 |         | Yes      |       1 | NO PAD        |
...
| utf8mb4_general_ci         | utf8mb4 |  45 |         | Yes      |       1 | PAD SPACE     |
...
| utf8mb4_spanish_ci         | utf8mb4 | 231 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_zh_0900_as_cs      | utf8mb4 | 308 |         | Yes      |       0 | NO PAD        |
+----------------------------+---------+-----+---------+----------+---------+---------------+
89 rows in set (0.00 sec)

上述代码块中展示了MySQL8.0中utf8mb4这个字符集的常用比较规则。这些比较规则是有规律的。

  • 比较规则的名称以其关联的字符集名称开头。
  • 后面紧跟着该比较规则所应用的语言,比如utf8mb4_spanish_ci表示西班牙语的比较规则。utf8mb4_general_ci是一种通用的比较规则。
  • 名称后缀表示该规则是否区分大小写、语言中的重音等。具体后缀如下表所示
后缀英文释义描述
_aiaccent insensitive不区分重音
_asaccent sensitive区分重音
_cicase insensitive不区分大小写
_cscase sensitive区分大小写
_binbinary以二进制方式比较

常用的字符集

计算机是美国人发明的,因此ACISS字符集中包含了26个英文字母和一些字符就足够美国人日常使用了。但是如果一些其他国家和地区想要使用计算机,就必须有一套包含自身语言的字符集,比如GBK、IOS-8859-1等字符集。以下是一些常用的字符集:

  • ASCII:包含128个字符,包括空格、标点符号、数字、大小写字母和一些不可见字符(回车、制表符等)。由于ASCII字符集总共才128个字符,所以使用**一个字节(8位)**就足够保存了。
  • GB2312:收录6763个汉字以及拉丁字母、希腊字母等,兼容ASCII字符集。使用GB2312编码时,如果该字符存在于ASCII字符集中,则使用一字节编码,否则采用两字节编码。这种使用不同不同字节数来表示一个字符的编码方式称为变长编码
  • GBK(国标扩展的首字母):GBK对GB2312进行了扩充,编码方式兼容GB2312。
  • Unicode:几乎收录了各个国家使用的字符,并且还在不断扩充。Unicode仅定义了字符和数值的映射关系。具体存储需要看是UTF-8、UTF-16、UTF-32等。
Unicode字符集

Unicode定义了映射关系,但是却没有规定如何存储。一个码值为 0x41 的字符,只需要 1字节 就可以存下,但是码值 0x9ED1 的字符需要 2字节 的空间才可以装下,而更靠后的字符可能会需要 3字节 甚至 4字节 的空间。

UTF-16 和 UTF-32

我们可以规定,一个字符使用四个字节存储,也就是 32 位,这样就能涵盖现有 Unicode 包含的所有字符,这种编码方式叫做 UTF-32(UCS Transformation Format 的缩写)。UTF-32 的规则虽然简单,但是缺陷也很明显,假设使用 UTF-32 和 ASCII 分别对一个只有西文字母的文档编码,前者需要花费的空间是后者的四倍(ASCII 每个字符只需要一个字节存储)。

UTF-16是一种变长字符编码, 它将字符编码成 2 字节 或者 4 字节。与UTF-32类似,同样存在着空间浪费的问题。

UTF-8

在存储和网络传输中,通常使用更为节省空间的变长编码方式 UTF-8,UTF-8 代表 8 位一组表示 Unicode 字符的格式,采用变长编码,使用 1 - 4 个字节来表示字符,比如下面这样:

'C' -> 01000011(十六进制为0x43) // 1字节
'斌' -> 11100110 10010110 10001100(十六进制为0xE6968C)  // 3字节 

变长编码通常需要存储表示字节数的信息,让计算机知道字符是以几个字节来存储的。

UTF-8用首字节的前几位表示编码的字节数:

  • 首字节以0开头,表示单字节编码
  • 首字节以110开头,表示双字节编码,后续字节以10开头
  • 首字节以1110开头,表示三字节编码,后续字节以10开头
  • 首字节以11110开头,表示四字节编码,后续字节以10开头

在这里插入图片描述

举个例子,就拿上方代码块的 ‘斌’ 这个字符,

  1. 通过中文转Unicode编码工具可知码值为 \u658C。

  2. 转换为二进制数01100101 10001100,我们得到码点后采用UTF-8将其存储到计算机中,我们需要16位有效比特位,从上图可以看出只要 3字节 即可表示。

  3. 将二进制数代入规则:1110 0110 1001 0110 1000 1100(红色字体为有效比特位)

字符集和比较规则的应用

各级别的字符集和比较规则

在MySQL中可以从服务器、数据库、表、列这几个维度分别设置和查看字符集及其比较规则。

服务器级别
系统变量描述
character_set_server服务器级别的字符集
collation_server服务器级别的比较规则

MySQL8.0中默认的服务器字符集为utf8mb4,比较规则为utf8mb4_0900_ai_ci

mysql> SHOW variables like 'character_set_server';
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| character_set_server | utf8mb4 |
+----------------------+---------+mysql> SHOW variables like 'collation_server';
+------------------+--------------------+
| Variable_name    | Value              |
+------------------+--------------------+
| collation_server | utf8mb4_0900_ai_ci |
+------------------+--------------------+ 

修改MySQL系统变量的方式可以通过启动选项或者在服务器程序运行过程中使用SET语句来修改。也可以修改配置文件的*[server]*组信息。

数据库级别

具体数据库的字符集和比较规则可以在创建是指定,创建后也可以通过ALTER语句来修改。

# 创建或修改数据库时指定字符集
(CREATE | ALTER) DATABASE 数据库名称[CHARACTER SET 字符集名称][COLLATE 比较规则名称];
系统变量描述
character_set_database当前数据库的字符集
collation_database当前数据库的比较规则

数据库级别的两个系统变量与服务器级别不同的是,这我们不能通过修改这两个变量的值来改变当前数据库的字符集和比较规则(修改可以通过ALTER语句)。

创建数据库时也可以不指定字符集和比较规则,这将默认使用服务器级别的值。

表级别

与数据库级别类似,表的字符集和比较规则也可以在创建表时指定,或创建后修改。

# 创建表时指定
CREATE TABLE 表名 (列信息)[CHARACTER SET 字符集名称][COLLATE 比较规则名称];# 修改表的字符集
ALTER TABLE 表名[CHARACTER SET 字符集名称][COLLATE 比较规则名称];	

创建数据库时同样可以不指定字符集和比较规则,这将继承数据库级别。

列级别

对于存储字符串的列,同一个表中不同的列可以有不同的字符集和比较规则。在创建和修改列的时候可以指定该列的字符集和比较规则。

# 创建时指定
CREATE TABLE 表名(列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],...
);# 修改列的字符集
ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集] [COLLATE 比较规则名称];

同样,如果没有指定,就会使用表级别的。需要注意的是,修改指定列的字符集时,如果列中存储的数据不能用修改后的字符集进行表示,则会发生错误,中断修改操作。

小结:各级别的字符集和比较规则
  • 如果创建或修改时没有显式指定字符集和比较规则,则默认使用的字符集和比较规则。
  • 如果创建时没有显式指定,则默认使用数据库的。
  • 如果创建数据库时没有显式指定,则该数据库默认使用服务器的。

知道列的字符集后,就能知道某个列存储的实际数据所占用的存储空间大小。

客户端和服务器通信过程中的字符集

什么是乱码?计算机对某个字节序列进行解码时,采用的字符集和编码时使用的字符集不一致,就会产生乱码。例如’我’在utf-8下字节序列为0xE68891,若采用GBK解码,会先读前两个字节。

客户端发送阶段

使用MySQL自带的mysql客户端程序发送请求时(如下图),客户端编码请求字符串时使用的字符集与操作系统当前使用的字符集一致。

在这里插入图片描述

在Windows系统中,可以在启动客户端时使用命令default-character-set指定字符集(Unix系统慎用,指定字符集与操作系统不一致时,会乱码)。

mysql --default-character-set=utf8

在连接服务端时,客户端将默认的字符集信息(或者通过上述方式指定字符集)与用户名、密码等信息一起发送给服务器。服务端收到后将character_set_clientcharacter_set_connetioncharacter_set_results这3个系统变量的值初始化为客户端传递的字符集,作用请参考 2.2.2 节。

服务端处理阶段
系统变量描述
character_set_client服务器认为请求是按照该系统变量指定的字符集进行编码
character_set_connection服务器处理请求时,把请求字节序列从character_set_client转换为character_set_connection对应的字符集
character_set_results服务器采用该系统变量指定的字符集对返回给客户端的字符串进行编码
  1. 接收请求

服务端接收到客户端的请求的字节序列时,根据系统变量character_set_client对应的字符集解码该字节序列,该变量是SESSION级别的,可以对不同客户端设置不同的解码规则。

  1. 处理请求

在真正处理请求时,又会将其转换为系统变量character_set_connection对应的字符集进行编码的字节序列,该变量也是SESSION级别的,与之配套的另一个变量是collation_connection

将字节序列根据 character_set_client 转码为 character_set_connection 是为了确保数据在不同环节中的一致性、避免字符集不匹配问题、提高系统的灵活性和兼容性。这样可以保证 MySQL 在处理请求时能够正确解析和处理不同字符集编码的数据,确保数据的完整性和准确性。

CREATE TABLE table1(col VARCHAR(100)
) ENGINE=InnoDB CHARSET=utf8;

假设当前的character_set_connectionGBK

当执行如下查询语句:

SELECT * FROM table1 WHERE col = '斌';

表中的col字段是UTF-8编码,但连接为GBK,在这种情况下,列的字符集和排序规则的优先级会更高,因此会将 ‘斌’ 从 GBK 转为 UTF-8 后,使用 c 列的比较规则进行比较。

  1. 返回结果

服务端将查询结果从对应列的字符集编码转换为character_set_results系统变量对应的字符集编码后的字节序列,之后再发送给客户端。该变量亦是SESSION级别的。

客户端接收结果阶段

在此阶段,客户端收到的响应也是一个字节序列。对于Windows系统,客户端会使用MySQL客户端的默认字符集来解码这个字节序列(启动项 –default-character-set)。但是 Unix 系统会使用系统默认编码直接输出到控制台,因此可能会产生乱码。如下场景:

  1. 查看当前操作系统的默认编码

在这里插入图片描述

  1. 在 Mac OS 启动MySQL客户端时使用 –default_character_set=gbk

  2. 客户端与服务端建立连接时指定了编码方式为 GBK ,因此服务端将会返回 GBK 编码后的字节序列。

在这里插入图片描述

  1. Mac OS 会直接将序列输出到终端,使用的是系统的编码 UTF-8 ,因此出现乱码(windows会使用客户端的编码)。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/719867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[LeetBook]【学习日记】数组内乘积

题目 按规则计算统计结果 为了深入了解这些生物群体的生态特征,你们进行了大量的实地观察和数据采集。数组 arrayA 记录了各个生物群体数量数据,其中 arrayA[i] 表示第 i 个生物群体的数量。请返回一个数组 arrayB,该数组为基于数组 arrayA …

常用Linux 命令汇总

1、基本命令 uname -m 显示机器的处理器架构 uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 (SMBIOS / DMI) hdparm -i /dev/hda 罗列一个磁盘的架构特性 hdparm -tT /dev/sda 在磁盘上执行测试性读取操作系统信息 arch 显示机器的处理器架构 uname -m 显示…

vue3项目tsconfig.js详解

Tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的配置来对代码的编译 {/*tsconfig.json是ts编译器的配置文件,ts编译器根据它的配置来编译ts文件"include"用来指定哪些ts文件要进行编译"exclude"用来指定那些ts文件不需要进…

分布式任务调度:XXL-Job入门介绍实战

1. 引言 随着互联网业务的不断扩展和复杂化,分布式任务调度成为了构建大规模系统的重要组成部分。XXL-Job作为一款开源的分布式任务调度平台,提供了完整的任务调度和管理功能,被广泛应用于各种场景。本文将介绍如何入门使用XXL-Job&#xff…

Python解释器及PyCharm安装教程

PyCharm官方下载地址☞https://www.jetbrains.com/pycharm/download/?sectionwindows Python解释器官方下载地址☞ https://www.python.org/downloads/windows/

牛客小白月赛60 C 小竹关禁闭(动态规划 01背包)

题目描述 妈妈成功将小竹救了出来,她觉得小竹实在是太笨了,决定关小竹一周禁闭。可是小竹哪里能忍受失去自由,他早就偷藏了一部手机用于联系你,请求你帮助他逃离。 你通过观察发现他房间内有 n n n 个可用于制成绳子的物品&…

数学建模【灰色关联分析】

一、灰色关联分析简介 一般的抽象系统,如社会系统、经济系统、农业系统、生态系统、教育系统等都包含有许多种因素,多种因素共同作用的结果决定了该系统的发展态势。人们常常希望知道在众多的因素中,哪些是主要因素,哪些是次要因素;哪些因素…

Android各版本差异性

Android各版本差异性 Android 6(api 23) 指纹识别 运行时权限:动态申请(重点) 移除对Apache HTTP client的支持,建议使用HttpURLConnection。 休眠和应用待机模式(Doze and App Standby&…

web学习笔记(二十三)

目录 1.增加节点 1.1document.write 1.2innerHTML 1.3动态添加 1.4追加和插入节点 2.删除、克隆、替换节点 2.1删除节点 2.2克隆节点 2.3替换节点 3.事件 3.1什么是事件 3.2事件三要素 3.3事件的种类 3.4常见事件名称(类型)汇总 4.操作…

代码随想录算法训练营第三十四天| 860.柠檬水找零, 406.根据身高重建队列 ,452. 用最少数量的箭引爆气球

860.柠檬水找零 - LeetCode 思路: 这个问题比较简单, 用一个字典bill_dict记录已经收到的钱已经钱的数量, 然后如果收到五元, 字典中的 bill_dict[5] 1。 收到10元 bill_dict[5] - 1 bill_dict[10] 1 。 麻烦的是收到20元&…

图像剪辑|Linux|ImageMagick的初步使用--素描,毛玻璃等特效

前言: ImageMagick在图像剪辑领域的地位基本等同于FFmpeg,和FFmpeg基本一样,在Linux下使用此工具的原因是该工具可以使用shell脚本批量剪辑,在Windows下就会比较麻烦一些了 那么,本文主要是记录一下ImageMagick的一些…

论文阅读:基于超像素的图卷积语义分割(图结构数据)

#Superpixel-based Graph Convolutional Network for Semantic Segmentation github链接 引言 GNN模型根据节点特征周围的边来训练节点特征,并获得最终的节点嵌入。通过利用具有不同滤波核的二维卷积对来自附近节点的信息进行整合,给定超像素方法生成的…

汽车上的各种质量:整备质量、总质量、装载质量、簧上质量

文章目录 前言一、整备质量二、额定总质量三、额定装载质量四、簧上质量 总结 前言 一、整备质量 整备质量指的是汽车按照出厂技术条件完全配备(包括备胎、工具、各种油水等)的质量。汽车的整备质量也就是人们常说的一辆汽车的自重,它的规范…

MATLAB--pie函数绘制复杂分类饼图(2)--附案例代码

MATLAB–pie函数绘制复杂分类数据的饼状图 目录 MATLAB--pie函数绘制复杂分类数据的饼状图摘要1. 问题描述2. 具体步骤:3. 绘制结果4. 小结 摘要 在数据可视化中,饼状图是一种常用的展示分类数据的方式。之前,文章介绍了使用MATLAB绘制饼状图…

数据删除

目录 数据删除 删除员工编号为 7369 的员工信息 删除若干个数据 删除公司中工资最高的员工 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 数据删除 删除数据就是指删除不再需要的数据 delete from 表名称 [where 删…

群晖Synology Drive服务搭建结合内网穿透实现云同步Obsidian笔记文件夹

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-ebec69DBjtGk7apF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

C++字典操作

创建字典 #include<iostream> #include<map> #include<string>using namespace std;int main(){map<string, int> mymap;}赋值 2.1 指定元素赋值 mymap["abc"] 1;2.2 添加键值对 mymap.insert(make_pair("bcd", 2));字典的顺序…

后端传给前端的时间字段前端显示不正确

具体问题是什么呢&#xff0c;就比如我后段有一个字段是TimeStamp类型&#xff0c;从数据库中查出数据是下面的样式&#xff1a; 但是前端显示的是下面的格式&#xff1a; 这个的解决方法还是挺多的&#xff0c;那接下来具体来看看吧~ 第一种&#xff1a; 在application.prop…

Linux使用bcache 将SSD加速硬盘

前言 在Linux下&#xff0c;使用SSD为HDD加速&#xff0c;目前较为成熟的方案有&#xff1a;flashcache&#xff0c;enhanceIO&#xff0c;dm-cache&#xff0c;bcache等&#xff0c;多方面比较以后最终选择了bcache。 bcache 是一个 Linux 内核块层超速缓存。它允许使用一个或…

Flink 面试题总结及答案

基础 state的分类 key state和operate state state 的重分布 Flink状态管理详解&#xff1a;Keyed State和Operator List State深度解析 - 掘金 checkpoint 和save point https://zhuanlan.zhihu.com/p/79526638 flink job 的容错策略 如果在没有持续消息输出的情况下&…