首页 / MySQL 入门教程 / 字符集与排序规则

MySQL 入门教程

字符集与排序规则

本教程共 46 篇 · 第 11 篇 · 更新于 2026-07-30 · 约 13 分钟阅读

MySQLMySQL 入门教程字符集排序规则utf8mb4collationemoji编码

11. 字符集与排序规则

本节目标:彻底搞懂 MySQL 的字符集(Character Set)和排序规则(Collation),明白 utf8mb4 和 utf8 到底差在哪、collation 命名怎么看、四个层级怎么设置,学会正确存中文和 emoji,告别乱码。

乱码是中文开发者绕不开的痛。明明能存中文,怎么存 emoji 就报错?为什么 WHERE name = 'Tom' 能查到 'tom'?这些都和字符集、排序规则有关。这一节把这些一次性讲透。

11.1 什么是字符集

字符集(Character Set) 是一套”字符和数字编码”的对应表。它规定了某个字符在计算机里用哪个数字表示。

比如 utf8mb4 字符集下:

  • A 对应数字 65;
  • 对应数字 20013;
  • emoji 😀 对应数字 128512。

字符集决定了”能存哪些字符”以及”每个字符占几个字节”。

查看 MySQL 支持的所有字符集:

SHOW CHARACTER SET;

输出(截选):

+----------+---------------------------+---------------------+--------+
| Charset  | Description               | Default collation   | Maxlen |
+----------+---------------------------+---------------------+--------+
| ascii    | US ASCII                  | ascii_general_ci    |      1 |
| latin1   | cp1252 West European      | latin1_swedish_ci   |      1 |
| utf8mb3  | UTF-8 Unicode             | utf8mb3_general_ci  |      3 |
| utf8mb4  | UTF-8 Unicode             | utf8mb4_0900_ai_ci  |      4 |
| binary   | Binary pseudo charset     | binary              |      1 |
+----------+---------------------------+---------------------+--------+

Maxlen 列很重要:一个字符最多占几个字节

11.2 utf8mb4 vs utf8:最关键的坑

这是新手必踩的坑,一定要讲清楚。

MySQL 里有两个长得像的字符集:

  • utf8(即 utf8mb3:最多 3 字节,存不下 emoji 和部分生僻字
  • utf8mb4:最多 4 字节,完整支持 Unicode,能存 emoji。
Warning

MySQL 里的 utf8 是”残废版”,最多 3 字节!而标准的 UTF-8 是 1~4 字节。所以在 MySQL 里说 utf8 ≠ 标准的 UTF-8。这就是为什么用 utf8 存 emoji 会报 Incorrect string value 错误。

版本演进:

  • 8.0 之前:默认字符集是 latin1utf8 指 3 字节版;
  • 8.0 起:默认字符集改成 utf8mb4,默认排序规则 utf8mb4_0900_ai_ci
  • 26.7:默认就是 utf8mb4
Tip

从 8.0 起,utf8 被当作 utf8mb3 的别名,官方计划未来把 utf8 改成指 utf8mb4。但只要你看到老教程写 utf8,一律在心里替换成 utf8mb4。新项目无脑用 utf8mb4

emoji 存储实验

-- 建表用 utf8mb4
CREATE TABLE users (
    id INT PRIMARY KEY,
    nickname VARCHAR(50)
) CHARACTER SET utf8mb4;

-- 存 emoji,没问题
INSERT INTO users VALUES(1, '码上学😀');

mysql> SELECT nickname FROM users;
+-----------+
| nickname  |
+-----------+
| 码上学😀  |
+-----------+

要是表用 utf8(utf8mb3),同样这条插入就报错。所以只要可能存 emoji、生僻字、多语言,就用 utf8mb4

11.3 什么是排序规则

排序规则(Collation) 是字符集的一套比较和排序规则。光有字符集知道”字符是啥”还不够,还得知道”字符之间怎么比大小、怎么排序”。

比如同样是 utf8mb4

  • utf8mb4_0900_ai_ci:不区分大小写、不区分重音(A = a = á);
  • utf8mb4_0900_as_cs:区分大小写、区分重音(A ≠ a ≠ á);
  • utf8mb4_bin:按二进制字节比较,最严格。

排序规则决定了两件事:

  1. 排序ORDER BY 时谁排前谁排后;
  2. 比较WHERE name = 'tom' 能不能匹配到 'Tom'

查看某个字符集有哪些排序规则:

SHOW COLLATION LIKE 'utf8mb4%';

11.4 排序规则的命名规则

排序规则的名字有固定格式,看懂后缀就明白它的行为:

字符集名_版本_敏感性后缀

常见后缀:

后缀含义示例
_ciCase Insensitive,不区分大小写utf8mb4_0900_ai_ci
_csCase Sensitive,区分大小写utf8mb4_0900_as_cs
_bin二进制比较,区分一切utf8mb4_bin
_aiAccent Insensitive,不区分重音(和 _ci 搭配)
_asAccent Sensitive,区分重音(和 _cs 搭配)

utf8mb4_0900_ai_ci 拆开看:

  • utf8mb4:字符集;
  • 0900:基于 UCA(Unicode Collation Algorithm)9.0.0 排序算法;
  • ai:不区分重音(a = á);
  • ci:不区分大小写(A = a)。

这是 8.0+ 的默认排序规则,也是 26.7 的默认值。

Note

默认的 _ci 排序规则意味着 WHERE name = 'Tom' 能查到 'tom''TOM'。如果你希望大小写敏感(比如用户名不能重复),要么改成 _cs/_bin,要么在查询时用 BINARY 强制比较:WHERE BINARY name = 'Tom'

11.5 字符集的四个层级

MySQL 的字符集可以在四个层级设置,优先级从高到低:列 > 表 > 数据库 > 服务器。低层级没指定就继承上一级。

服务器级

服务器启动时设定的全局字符集,影响所有新库。在 my.cnf 配置:

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

[client]
default-character-set=utf8mb4

查看当前服务器字符集:

SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';

数据库级

建库时指定,没指定就继承服务器级:

CREATE DATABASE shop
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;

改库的字符集:

ALTER DATABASE shop CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
Warning

改库字符集只影响之后新建的表,已存在的表不会自动跟着变。要改旧表,得逐个 ALTER TABLE 转换。

表级

建表时指定,没指定就继承库级:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CHARSETCHARACTER SET 的简写,效果一样。

列级

只给某个字符串列单独指定:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
);

这样 name 列就是二进制比较,区分大小写,而其他列继承表的设置。

Tip

列级设置优先级最高。如果某列需要特殊比较规则(如密码列要区分大小写),单独给这列设 utf8mb4_bin 即可,不用动整张表。

11.6 连接字符集:客户端和服务端要对上

还有一个容易出乱码的地方:客户端和服务端之间的字符集。如果客户端用 UTF-8 发数据,服务端当成 latin1 接收,就会乱码。

相关变量:

  • character_set_client:客户端发来的数据是什么字符集;
  • character_set_connection:连接层用的字符集;
  • character_set_results:返回结果给客户端时用的字符集。

最省事的做法是统一用一条命令把这三者设成 utf8mb4:

SET NAMES utf8mb4;

或者在连接时指定:

mysql --default-character-set=utf8mb4 -u root -p
Note

SET NAMES utf8mb4 不是改服务器或库的字符集,它只影响”这次连接怎么收发数据”。每次连接都要设,或写进配置文件一劳永逸。

11.7 查看字符集的常用命令

汇总几个排查乱码时必用的命令:

-- 服务器字符集和排序规则
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';

-- 当前连接相关字符集
SHOW VARIABLES LIKE 'character_set%';

-- 某个库的字符集
SHOW CREATE DATABASE shop;

-- 某张表的字符集
SHOW CREATE TABLE users;

-- 某列的字符集(看 Collation 列)
SHOW FULL COLUMNS FROM users;
Tip

遇到乱码,按这个顺序查:连接字符集 -> 库字符集 -> 表字符集 -> 列字符集。只要有一环不对,就可能乱码。统一成 utf8mb4 基本能根治。

11.8 转换字符集:CONVERT 和 CAST

已经存了 latin1 的数据要转成 utf8mb4,用 CONVERTCAST 函数:

-- 转换字符串的字符集
SELECT CONVERT('abc' USING utf8mb4);

-- 用 CAST
SELECT CAST('abc' AS CHAR CHARACTER SET utf8mb4);

把整张表的列转字符集:

-- 把 name 列转成 utf8mb4
ALTER TABLE users MODIFY name VARCHAR(50) CHARACTER SET utf8mb4;
Warning

字符集转换要小心”丢字符”:如果原数据里有目标字符集表示不了的字符,转换会变成问号 ?。一般 latin1 -> utf8mb4 安全,反过来不一定。转换前务必备份。

11.9 一个完整的”中文不乱码”配置

把这一节学到的串起来,给一个生产可用的配置:

my.cnf / my.ini:

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

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

建库建表:

CREATE DATABASE shop
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;

USE shop;

CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    nickname VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

连接时:

SET NAMES utf8mb4;

这样从服务器到库到表到连接,全链路 utf8mb4,中文、emoji 都不会再乱码。

11.10 小结

这一节理清了字符集和排序规则:

  • 字符集决定能存什么字符、占多少字节;
  • MySQL 的 utf8 是 3 字节残废版,统一用 utf8mb4
  • 8.0+/26.7 默认字符集 utf8mb4,默认排序规则 utf8mb4_0900_ai_ci
  • 排序规则后缀 _ci 不区分大小写、_cs 区分、_bin 二进制;
  • 字符集四级:服务器 < 数据库 < 表 < 列,列优先级最高;
  • SET NAMES utf8mb4 统一连接字符集,根治乱码;
  • 转换字符集用 CONVERT/CAST,转换前要备份。

数据类型和字符集都讲完了,下一节终于开始建表了。