暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

3、mysql字符集与比较规则

JAVA技术百科 2021-04-07
1014

概念介绍

字符编解码

我们知道不管是计算机存储还是网络上传输数据,其中传输的都是0101的二进制流。所以我们平时在网上收发消息,电脑上保存文本最终都是以二进制流的形式传输或存储。

在这个过程中,我们以小明要给小红发送一个消息为例,小明在对话框中输入一句话,需要经过聊天软件进行编码成二进制流,通过网卡,经过网络发送给小红,小红在收到二进制流后,对二进制流进行相应的解码,就能看到小明发送的消息了。在这个过程中,对二进制流的解析方式必须是相同的,否则就会出现乱码的情况。这个方式就是字符串的编码格式。用代码表示:

    @Test
public void testCharset(){
String str = "明天我们一起学习";
byte[] strDecodedBytes = str.getBytes(Charset.forName("utf-8"));
System.out.println("字符串的16进制表示:"+bytesToHexString(strDecodedBytes));
String encodedStr = new String(strDecodedBytes,Charset.forName("GBK"));
System.out.println(encodedStr);
}

复制

输出:字符串的16进制表示:e6988ee5a4a9e68891e4bbace4b880e8b5b7e5ada6e4b9a0

鏄庡ぉ鎴戜滑涓�璧峰涔�

常见的编码格式介绍

常见的编码格式主要有:ASCII、ISO 8859-1、GBK、UTF-8

在工作中,我们接触的最多的应该就是UTF-8了,它的全称是Unicode Transformation Format,通用转换格式,它几乎可以表达任何字符文字,同时兼容ASCII码,它采用变长编码格式,编码一个字符需要1-3个字节。

小贴士:在mysql中,还有utf8mb4,这种格式比utf8包含的字符集还要全面,占用1-4个字节。

ASCII:收录了一些字母大小写、空格、回车等,总共128个字符,所以每个字符只需要1个字节就可以表示。

ISO 8859-1:是在ASCII的基础上,加入了一些德国、法国的字母,加起来总共256个,每个字符占1个字节。有时我们也叫ISO 8859-1为Latin1.

GBK:国标,主要用于汉字的编解码,同时兼容ASCII以及ISO的一些国际标准,每个字符占2个字节。

比较规则

就是我们平时比对字符串大小的时候,如果判断哪个字符串大,哪个小。比如是否区分大小写啊,是否区分重音,是比较字符呢还是二进制呢?等等。在后面我会具体介绍。

mysql的字符集与比较规则

mysql有哪些维度的字符集

我们知道,在mysql中会碰到很多字符集的问题,采用不恰当的字符集可能会导致存入的数据或查出来的数据是乱码的问题。

在mysql中,字符集主要有以下几个维度:

服务器级别 server数据库级别 database表级别 table列级别 column

话不多说,我们来看看我机子上的mysql的字符编码格式:我们用:

show variables like '%character_set%';

把字符集相关的系统变量都查出来看看

server级别:character_set_server database级别:character_set_database我们看了server和database的字符集编码之后,再选一张表进行查看:

show table status from dwsbf_nw like '%dwsbf_sjtb%';

可惜,我们好像没有找到与charset相关的状态变量,只看到了比较规则为utf8mb4-bin.从比较规则中,我们也能够知道,该表的字符集采用的是utf8mb4,继承了database的字符集。原因是比较规则是和字符集配套使用的。

列的字符集:

show full columns from dwsbf_nw.dwsbf_sjtb;

列的编码格式为utf8mb4,继承了表的默认字符集。同时我们看到有些字段在比较规则列为null,原因是他们不是字符串,他们是数字和时间date,不需要字符串的比较规则。

在上面的介绍中,我多次提到了继承这个词,是的。在这些字符集中,是存在继承关系的,具体的顺序就是我前面说的顺序:

服务器级别 server数据库级别 database表级别 table列级别 column

举个例子,如果你没有在创建数据库的时候明确指定字符集, 如:CREATE DATABASE 数据库名; 那么默认使用的就是服务器的字符集。同理,如果你在创建表的时候没有明确指定字符集,默认采用的就是数据库的字符集。

在文末,我将会把自定义字符集的sql使用方式写一下,如需自取。

一次sql查询经历了怎样的编解码过程,由哪些参数决定

直接说答案:一次sql查询主要与三个字符集的系统变量有关,分别为character_set_client、character_set_connection、character_set_results,见名思意:具体的逻辑呢?首先client一般会发送一条sql给客户端,比如select * from tableA where name = '蜗牛';,在分析的过程中,我们主要对查询参数“蜗牛”进行分析。

1、首先蜗牛两个字被client端进行编码为二进制流,传输给服务器。

2、服务器收到后,会认为客户端的编码为character_set_client对蜗牛进行解码,获取client发送的字符串sql。

3、解码之后,再把sql转换为character_set_connection格式,使得能与数据库连接的字符集相同。

4、解码成character_set_connection之后,就进行数据比对查询。此时如果要比对的列的字符集与character_set_connection不相等,那显然就是会有问题的。

5、数据查询出来之后,对结果要进行编码,编码的字符集就采用character_set_results字符集,此时如果客户端接收的字符集与character_set_connection不相同,那么客户端解码的数据也会出现问题。

是不是有点绕,最简单的做法就是,啥也别说了,大家都用utf8mb4或utf8吧。

比较规则举例

从前面的分析我们能看出,其实比较规则和字符集是有关系的,每种字符集会有一种默认的比较规则,如果我们不指定比较规则的话,就采用默认的比较规则。

SHOW COLLATION LIKE 'utf8_%';

我们来看看utf8的比较规则:很多,有二十多种。比较规则的命名比较有规律,为 字符集_语言_类型 ,类型主要为是否区分大小写这些。如:utf8_spanish_ci是以西班牙语的规则比较,utf8_general_ci是通用的比较规则。

常见的类型,如:_ci 为case insensitive,大小写敏感,区分大小写。_cs 为case sensitive,区分大小写。_ai 为accent insensitive, 不区分重音 _as 为accent sensitive ,区分重音

自定义字符集与比较规则的sql

数据库级别:

CREATE DATABASE 数据库名 [[DEFAULT] CHARACTER SET 字符集名称] [[DEFAULT] COLLATE 比较规则名称];

ALTER DATABASE 数据库名 [[DEFAULT] CHARACTER SET 字符集名称] [[DEFAULT] COLLATE 比较规则名称];

如:

CREATE DATABASE charset_demo_db CHARACTER SET gb2312 COLLATE gb2312_chinese_ci;

表级别:CREATE TABLE 表名 (列的信息) [[DEFAULT] CHARACTER SET 字符集名称] [COLLATE 比较规则名称]]

ALTER TABLE 表名 [[DEFAULT] CHARACTER SET 字符集名称] [COLLATE 比较规则名称]

如:

CREATE TABLE t( col VARCHAR(10)) CHARACTER SET utf8 COLLATE utf8_general_ci;

列级别:CREATE TABLE 表名( 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称], 其他列... );

ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];

如:

ALTER TABLE t MODIFY col VARCHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci;


文章转载自JAVA技术百科,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论