mysql字符集(character sets)是指一系列符号以及符号对应的编码的集合,比如英文字母可以用ASCII编码,中文可以用GBK或者UTF8编码。校对规则(collations)则是指一种比较字符的规则,这种比较规则决定了mysql如何进行排序以及如何对字符比较大小。

mysql的character sets和collations有很多种,而且可以在多个维度去配置,包含服务器的配置和客户端的配置,对于初学者往往容易搞混,有时候出了乱码等问题也不知道怎么排查。今天笔者就详细梳理一下mysql中的character sets和collations。

我们先来看看mysql都可以配置哪些字符集,输入如下命令查看。

show variables like '%character%';

可以看到,有多达7个的character_set相关的参数,接下来我们就详细说说这些参数。

查看mysql中支持的字符集和校对规则

mysql中每个字符集都会对应多个校对规则,是一对多的关系。比如utf8对应的collation有utf8_general_ci,utf8_bin,utf8_unicode_ci等。而且每个character set会有个默认的collation与之对应,当我们在创建数据库或者创建表时如果只指定character set,不指定collation,就会使用character set默认的collation。collation的命名是以对应的character set为开头,比如collation为utf8_general_ci,我们就知道这个collation对应的字符集是utf8。

查看字符集

2种方式可以查看mysql中支持哪些字符集

1. 通过INFORMATION_SCHEMA.CHARACTER_SETS表来查看

2. 通过SHOW CHARACTER SET来查看,和上面表的结果是一样的。

查看collations

通过 show collation 查看校对规则有哪些,还可在语句后面加where条件筛选。

配置与查看字符集与校对规则

服务器端相关character set和collation

mysql服务器端相关字符集是服务器对数据的存储等相关的字符集,不涉及客户端的问题。

mysql服务器端的字符集和校对规则可以在四个级别指定:server, database, table, column

server级别

在mysql5.7中,server character set 和 server collation 默认为 latin1 和 latin1_swedish_ci,在mysql8中,默认为utf8mb4 和 utf8mb4_0900_ai_ci

如果想要修改server级别的character set和collation,可以在启动时指定参数

 mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci

或者将上面的参数写入到my.ini中[mysqld]下面,如下图。

server级别的character set和collation的作用是为创建数据库(CREAT DATABASE)时指定默认字符集和校对规则。也就是说创建数据库时如果没有指定character set和collation,就默认使用server级别的。

server级别的character set 和 collation可通过如下命令查看

show variables like 'character_set_server'
show variables like 'collation_server'

database级别

数据库级别的character set和collation可以在创建和修改数据库时指定,如果不指定,则使用server级别的。

CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name]ALTER DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name]举例:create database demo character set utf8 collate utf8_general_ci;

数据库的character set和collation可通过INFORMATION_SCHEMA.SCHEMATA表查看。

比如下图,我创建了三个数据库test, test2, test3,test数据库的character set和collation分别为utf8和utf8_general_ci,而test2和test3数据库的character set和collation分别为latin1和latin1_swedish_ci。

也可以通过如下方式查看

USE db_name;
SELECT @@character_set_database, @@collation_database;

数据库级别的character set和collation会影响以下行为:

1. 创建表时,会默认使用database的character set和collation。

2. 使用mysql的LOAD DATA加载数据时,默认采用database的character set和collation。

3. 作用于存储过程和函数,在创建存储过程和函数时,传递的参数默认采用database的character set。

比如我的database character set为latin1,然后我创建一个存储过程proc1(nameStr varchar(20)),当我调用存储过程call proc1('张三')时,会报错,因为存储过程proc1的参数只支持latin1字符集。

table级别

table的character set和collation可在创建表时指定,不指定默认采用database级别的。

CREATE TABLE tbl_name (column_list)[[DEFAULT] CHARACTER SET charset_name][COLLATE collation_name]]ALTER TABLE tbl_name[[DEFAULT] CHARACTER SET charset_name][COLLATE collation_name]

table级别的character set和collation会影响column级别的character set和collation,也就是column如果不指定character set和collation,就会默认继承table级别的。

要想查看表的character set和collation,可通过information_schema.TABLES表查看,不过这个表只保存了collation信息,但是通过collation我们就能知道character set是什么了。

或者通过如下命令查看

column级别

指定column级别的character set和collation,只有column的类型为字符型,如char,varchar,text等时,才可指定character set和collation。

col_name {CHAR | VARCHAR | TEXT} (col_length)[CHARACTER SET charset_name][COLLATE collation_name]举例
CREATE TABLE t1
(col1 VARCHAR(5)CHARACTER SET latin1COLLATE latin1_german1_ci
);ALTER TABLE t1 MODIFYcol1 VARCHAR(5)CHARACTER SET latin1COLLATE latin1_swedish_ci;

要查看列的character set和collation,可通过information_schema.COLUMNS表查看。

客户端相关character set和collation

客户端可能和mysql服务器采用不同的字符集,比如我们的java应用用的是一套字符集,mysql服务器用的是另一套字符集,这种情况下就要指定客户端和服务器连接交互时的字符集。和客户端相关的字符集配置有3个参数:character_set_client、character_set_connection、character_set_results。

这3个参数都是session级别的,也就是说不同的客户端连接时可以把这3个参数指定为不同的值,而且在客户端和服务器连接建立成功后,可以动态修改这3个值,不需要重启mysql。

参数作用

mysql服务器把从客户端接收的数据从character_set_client 转成 character_set_connection,然后进行后续处理。把查询结果转成character_set_results返回给客户端。所以character_set_client和character_set_connection是在向mysql发送命令的时候起作用,character_set_results是在接收mysql数据时起作用。

参数查看与设置

在连接mysql成功后,通过如下2种方式查看这三个参数的值。

方式一:

SELECT * FROM performance_schema.session_variables
WHERE VARIABLE_NAME IN (
'character_set_client', 'character_set_connection',
'character_set_results', 'collation_connection'
) ORDER BY VARIABLE_NAME;

方式二:

SHOW SESSION VARIABLES LIKE 'character\_set\_%';
SHOW SESSION VARIABLES LIKE 'collation\_%';

设置这三个参数的值有以下3种方式。

方式一:

在mysql客户端连接时指定,可以配置在my.ini中,或者写在命令行后面。

[mysql]

default-character-set=utf8

mysql -uroot -p --default-character-set=utf8

方式二:

set names charset_name

这个命令等同于如下命令

SET character_set_client = charset_name;

SET character_set_results = charset_name;

SET character_set_connection = charset_name;

方式三:

set character set charset_name,注意区分和set names的区别。这个命令会把character_set_connection设置为和database一样,而不是指定的charset_name。

等于如下命令。

SET character_set_client = charset_name;

SET character_set_results = charset_name;

SET collation_connection = @@collation_database;

character_set_client、character_set_connection、character_set_results深入理解

一般我们把character_set_client、character_set_connection、character_set_results这三个值设置为一样的比较好,这样可以避免不必要的麻烦。但是具体这几个参数怎样在发挥作用,下面我们通过几个例子来看一下。注意,下面的例子可能会比较容易把人绕晕,如果不感兴趣,可以不看。上面讲解的关于字符集和校对规则的知识应该可以应对日常开发了。

character_set_results参数作用示例

这里我们可以做个试验加深理解,我们先试验一下character_set_results。

我们建一个表,字符集设置为utf8,在表中插入一行数据。注意我这里插入数据是用的mysql 连接工具datagrip,没有在cmd窗口中用mysql命令行,因为用命令行可能会影响后面的分析结果。

create table demo
(id int auto_increment,name varchar(20) null,constraint demo_pkprimary key (id)
) character set utf8;
insert into demo(name) value ('gitcat熊');

然后我们打开cmd窗口,连接mysql服务器。可以看到,连接好后,默认的character_set_client、character_set_connection、character_set_results都是gbk,这是因为windows系统默认的编码是gbk。

然后我们查询数据看看。可以看到中文可以正常显示。这是因为mysql server端demo表的编码是utf8,但是character_set_results配置的是gbk,所以mysql在返回数据之前把查出的数据转成了gbk,又因为我们cmd窗口是以gbk编码的,所以就正常显示出了数据。

我们把character_set_results设置成utf8再看看。可以看到显示出问题了。因为我们告诉mysql server character_set_results=utf8,所以mysql就会把查询结果转成utf8返回给我们,但是我们的cmd窗口是gbk编码的,窗口会按照gbk解码数据显示,自然就显示出问题了。

我们可以验证一下。熊的utf8编码为E7868A,我们把这个编码转成gbk看看,因为gbk是两个字节为单位编码,所以我们先查询一下gbk编码E786对应的字是什么,从下图可以看到正好是我们返回的select结果的第一个汉字“鐔”,然后再查一下8A,查不到可显示的字符,因为GBK的编码范围是在8140-FEFE,所以返回结果显示了个“□”。

接下来我们把当前cmd窗口修改成用utf8编码显示,设置方式网上有很多,就是在cmd窗口执行一下命令 chcp 65001,会打开一个新的窗口,我们在新窗口重新连接mysql,可以看到,连接后的默认编码已经变成utf8了。

这时我们再查询一下,可以看到可以正常显示。

这时如果我们把character_set_results设置成gbk,反而不能正常显示了。因为我设置character_set_results=gbk,mysql server就会认为你要把查询结果转成gbk,mysql server好心把结果给你转成gbk了,结果你的窗口又以utf8解码来显示,当然就出问题了。 熊的gbk编码是D0DC,ÐÜ对应的unicode,正好也是D0和DC,印证了mysql服务器确实把熊这个字转成gbk编码传给我们了。

细心的网友可能会发现,这里有个问题,就是为什么cmd窗口是以unicode解码的,而不是utf8?因为我们返回的数据格式不符合utf8规则!

utf8编码规则如下,可以看到,不是随便给个2字节或者3字节的编码,都能用utf8来解析出字符。所以猜测cmd窗口对于不能用utf8解析的编码,只能以unicode来解码了。如果我们返回的编码正好是符合utf8规则的,那么cmd窗口就会以utf8正确解析出结果。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
以汉字“严”为例,演示如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),
根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),
因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。
然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。
这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

真的如我们猜测的这样吗?我们可以继续做试验来看。请接着往下看,下面会更精彩!

我们可以来做个实验验证上面我们的猜想。还是保持我们上面的实验环境,即cmd窗口是utf8模式,设置character_set_results=gbk,然后我们在数据表demo中插入如下一条数据,注意我插入数据用的是datagrip,不是在当前cmd窗口,因为当前cmd窗口我们修改了一些参数,直接在这里插入会影响我们分析。

insert into demo(name) values('鍦ㄥ悧');

然后查询一下结果。

很神奇,竟然没有"乱码",当然其实是乱码了,因为和我们数据库中存入的结果不一样了。我们分析一下这里发生了什么。

首先mysql server从数据库中查出"鍦ㄥ悧"这3个字,然后发现character_set_results=gbk,好吧,那mysql server就按照要求,把这3个字转成gbk格式发送给客户端,这3个字对应的gbk编码是E59C(鍦)A8E5(ㄥ)9097(悧),现在cmd窗口接收到这个编码了,要显示在屏幕上了,因为cmd窗口设置的是utf8编码,所以就以utf8方式来解析收到的编码E59CA8E59097,而这一串编码正好对应utf8中的"在吗"。这也印证了我们之前的猜想,如果server传回来的数据是符合utf8编码规则的,cmd窗口就会以utf8规则帮我们解码出数据显示。

character_set_client、character_set_connection参数作用

接下来我们试验一下character_set_client、character_set_connection这两个参数的设置对数据的影响。前面说了,server把从客户端接收的数据从character_set_client 转成character_set_connection,比如我们发送了一条insert语句,mysql server就会以为,你发送的语句是用character_set_client编码的,但是我要转成character_set_connection,然后再执行插入语句。

我们还是先以默认方式连接mysql数据库,如下。

然后在我们上面建的demo表里插入一条数据。可以看到,数据被正确地插入和读出。因为我们当前窗口的编码是gbk,而设置的character_set_client和character_set_connection也是gbk,所以mysql就会把我们的数据从gbk转成gbk,再存入数据库,当然就没问题了。当然存入数据库时发现表的编码是utf8,所以其实这里又转成utf8存入数据库的,这一步和character_set_client和character_set_connection就没关系了,我们先不深究。

接下来继续试验,这里只说一下结果,就不截图了。

cmd窗口为gbk编码时的情况

1. 如果cmd窗口是gbk编码,character_set_client是gbk,character_set_connection是utf8,插入和查询也没问题。

2. 如果cmd窗口是gbk编码,character_set_client是utf8,character_set_connection是utf8,插入无法插入,会报错如下。

我们来分析一下这种情况,因为当前窗口是gbk编码,所以传给server的编码是gbk的,但是因为character_set_client=utf8,server误以为是utf8的,按照utf8来解码,发现和utf8编码规则不符合,所以报错了。如果我们传给server的gbk编码正好也符合utf8编码,server是不会报错的,会插入成功,只是插入的数据不是我们预期的。比如下图的例子,我们还是以“鍦ㄥ悧”这三个字举例,如前所述,“鍦ㄥ悧”这三个字的gbk编码是E59C(鍦)A8E5(ㄥ)9097(悧),而这个编码正好也符合的utf8的编码,server在拿到这个编码后,按照utf8的规则解码可以解码成功,并且解码出来是“在吗”,于是就不会报错了。

3. 如果cmd窗口是gbk编码,character_set_client是utf8,character_set_connection是gbk,这种情况可以插入数据,但是插入的数据不对。

因为我们gbk编码的熊字不能正确被解码为utf8,所以在解码为utf8时就已经乱码了,后面所有的操作都会是乱码的,所以数据是不对的。

cmd窗口为utf8编码时的情况

1. 如果cmd窗口是utf8编码,character_set_client和character_set_connection设置成utf8,毫无疑问,这种情况肯定是没问题的,因为我们用的编码都一样。

2. 如果cmd窗口是utf8编码,character_set_client=gbk和character_set_connection=utf8,结果如下,可以看到utf8编码的熊为E7868A,E786正好对应gbk的"鐔",说明server是按照gbk解码了utf8编码的数据。

下面附一张在情况2这种情况下的另一个插入语句,有了前面我们的分析,你能明白结果为什么是这样了吗?

3. 如果cmd窗口是utf8编码,character_set_client=gbk和character_set_connection=gbk,2次插入语句结果分别如下。

4. 如果cmd窗口是utf8编码,character_set_client=utf8和character_set_connection=gbk,结果如下。

情况3和情况4大家可以根据前面的分析自己分析一下结果,看看是否理解了。

mysql字符集和校对规则(character sets and collations)详解相关推荐

  1. MySQL字符集和校对规则(Collation)

    MySQL字符集和校对规则(Collation) 阅读目录:MySQL的字符集和校对规则 MySQL的字符集 MySQL与字符集 正确使用字符集 MySQL客户端与字符集 字符集编码转换原理 字符集常 ...

  2. mysql字符集和校对规则

    字符集的概念大家都清楚,校对规则很多人不了解,一般数据库开发中也用不到这个概念,mysql在这方便貌似很先进,大概介绍一下. 简要说明 字符集和校对规则 字符集是一套符号和编码.校对规则是在字符集内用 ...

  3. mysql 字符集和校对规则

    为什么80%的码农都做不了架构师?>>>    1,常规字符集及校对 假设我们有一个字母表使用了四个字母:'A'.'B'.'a'.'b'.我们为每个字母赋予一个数值:'A'=0,'B ...

  4. 11、MySQL字符集和校对规则详解

    在讲解字符集和校对规则之前,我们先来简单了解一下字符.字符集和字符编码. 字符(Character)是计算机中字母.数字.符号的统称,一个字符可以是一个中文汉字.一个英文字母.一个阿拉伯数字.一个标点 ...

  5. MySQL数据库——MySQL字符集和校对规则详解

    在讲解字符集和校对规则之前,我们先来简单了解一下字符.字符集和字符编码. 字符(Character)是计算机中字母.数字.符号的统称,一个字符可以是一个中文汉字.一个英文字母.一个阿拉伯数字.一个标点 ...

  6. mysql连接校对_mysql字符集和校对规则(Mysql校对集)

    字符集的概念大家都清楚,校对规则很多人不了解,一般数据库开发中也用不到这个概念,mysql在这方便貌似很先进,大概介绍一下 简要说明 字符集和校对规则 字符集是一套符号和编码.校对规则是在字符集内用于 ...

  7. mysql字符集与校对规则设置_mysql中的字符集和校对规则(mysql校对集)

    1.简要说明介绍 字符集和校对规则 字符集是一套符号和编码.校对规则是在字符集内用于比较字符的一套规则. MySql在collation提供较强的支持,oracel在这方面没查到相应的资料. 不同字符 ...

  8. mysql干货——数据库字符集和校对规则详解

    2019独角兽企业重金招聘Python工程师标准>>> 一.什么是字符集 字符是多个文字和符号的总称,包括各个国家的文字.标点符号.图形符号.数字等.字符集多个字符的集合. 字符集合 ...

  9. 13、设置默认字符集和校对规则

    MySQL 服务器可以支持多种字符集,在同一台服务器.同一个数据库甚至同一个表的不同字段中,都可以使用不同的字符集.Oracle 等其它数据库管理系统都只能使用相同的字符集,相比之下,MySQL 明显 ...

  10. 12、查看字符集和校对规则

    本节主要介绍查看字符集和校对规则的几种方法. 在 MySQL 中,查看可用字符集的命令和执行过程如下: mysql> SHOW CHARACTER set; +----------+------ ...

最新文章

  1. 《linux c编程指南》学习手记5
  2. Socket send函数和recv函数详解
  3. 缓存-分布式锁-Redisson-信号量测试
  4. HDU2665(函数式线段树-区间第K大)
  5. RuntimeError: Exporting the operator var to ONNX opset version 11 is not supported. Please open a bu
  6. cubase计算机音乐,Cubase与Nuendo电脑音乐制作从新手到高手 (200例)
  7. windows命令和linux,WSL 命令行参考 | Microsoft Docs
  8. 前端实现内网在线excel编辑和word在线编辑相关建议
  9. android动态指示箭头,自定义选项卡指示器(箭头向下指示器)
  10. HMS Core线上Codelabs挑战赛第二期开始
  11. 万兆电口网卡性能分析
  12. 5G系统——MICO模式
  13. 1034: 夏季促销 C语言
  14. STC89C52的中断
  15. MultiValueMap
  16. 51单片机74ls273并行输出地址c语言程序,跑马灯/输入输出接口(片选地址74LS273)...
  17. 【腾讯云】Ubuntu16.04下搭建Java开发环境一站式服务(WinSCP、PuTTY、JDK、MySQL、Tomcat)
  18. 黑链暗链事件的爆发式增长
  19. 长三角一体化行动计划:布局世界级新零售网络
  20. carbide.c++ 如何生成sisx文件

热门文章

  1. 百度SiteApp构建网站APP
  2. html5音频剪辑,访谈类音频剪辑的5个小贴士
  3. 计算机论文英语单词,英语单词
  4. 最近智商拙计,做做题补一下
  5. 【题解】【AcWing】149. 荷马史诗
  6. 计算机cpu属于什么症状,电脑CPU超频过度有什么表现
  7. android7.0root工具,KingRoot全球实现Android 7.0一键 Root
  8. 数论整理之费马小定理
  9. 【Matlab水果蔬菜识别】灰度+二值化+腐蚀+直方图处理水果蔬菜识别【含GUI源码 1052期】
  10. 猿创征文|走技术创新路,展时代宏图梦