MySQL 字符集探秘:从 UTF-8 到 UTF8MB4,以及如何存储 Emoji

MySQL 字符集探秘:从 UTF-8 到 UTF8MB4,以及如何存储 Emoji

在 MySQL 数据库开发中,字符集(Character Set)和排序规则(Collation)是我们经常会遇到的配置项。比如定义一个字段时,我们可能会写出这样的语句:

sql 复制代码
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '用户名'

看到这里,你可能会疑惑:字符集到底是什么?utf8mb4 和常见的 utf8 有什么区别?如果我想存储 Emoji 表情或者其他特殊字符,又该如何选择合适的字符集?别急,这篇博客将带你一步步揭开 MySQL 字符集的面纱,并横向对比几种常见的字符集,帮助你做出明智的选择。

一、字符集的基础知识

什么是字符集?

简单来说,字符集就是一组字符和它们对应的编码规则。计算机本质上只认识二进制(0 和 1),而我们人类使用的文字(比如汉字、英文、符号)需要通过某种编码方式转化成二进制,计算机才能存储和处理。字符集的作用就是定义这种转化规则。

Unicode 和它的编码方式

提到字符集,就不得不说 Unicode 。Unicode 是一个庞大的字符集,它试图为世界上所有的字符分配一个唯一的编号(称为"码点",比如 U+0041 表示大写字母 A)。但 Unicode 本身并不规定这些码点如何存储成二进制,这就需要具体的编码方式,比如 UTF-8UTF-16UTF-32

  • UTF-8:一种变长编码方式。常用字符(比如英文)用 1 个字节存储,汉字通常用 3 个字节,某些特殊字符可能用 4 个字节。它节省空间,广泛用于互联网。
  • UTF-16:通常用 2 个字节存储一个字符,但对于罕见字符需要 4 个字节。
  • UTF-32:固定用 4 个字节存储每个字符,简单但占用空间大。

在 MySQL 中,我们最常用的是 UTF-8 相关的字符集。但 MySQL 的实现有点"历史包袱",接下来我们具体聊聊。

二、MySQL 中的 UTF8 和 UTF8MB4

MySQL 的 UTF8:一个"残缺"的实现

在 MySQL 中,utf8 字符集并不是完整的 UTF-8 编码。它只支持最多 3 个字节的字符,对应 Unicode 的基本多文种平面(BMP,码点范围 U+0000U+FFFF)。这包括英文、汉字和大部分常用符号,但不包括一些扩展字符,比如 Emoji(它们在 Unicode 的补充平面中,通常需要 4 个字节)。

UTF8MB4:真正的 UTF-8

utf8mb4 是 MySQL 对完整 UTF-8 的支持,名字中的 "mb4" 是 "maximum 4 bytes" 的缩写,意思是它支持最多 4 个字节的字符编码。这涵盖了 Unicode 的所有码点(U+0000U+10FFFF),包括 Emoji、一些生僻汉字和特殊符号。

举个例子:

  • 一个英文字符 "A" 在 utf8utf8mb4 中都占 1 个字节。
  • 一个汉字 "你" 在两者中都占 3 个字节。
  • 一个 Emoji "😊" 在 utf8 中无法存储(会报错或变成乱码),而在 utf8mb4 中占 4 个字节。

所以,utf8mb4 是 MySQL 中推荐的字符集,尤其是当你的应用需要国际化或支持复杂字符时。

Collation 是什么?

在字段定义中,除了 CHARACTER SET utf8mb4,你还会看到 COLLATE utf8mb4_0900_ai_ci。Collation 是排序规则,决定了字符如何比较和排序。utf8mb4_0900_ai_ci 的含义是:

  • 0900:基于 Unicode 9.0 的排序算法。
  • ai:accent insensitive,不区分重音(如 é 和 e 视为相等)。
  • ci:case insensitive,不区分大小写(如 A 和 a 视为相等)。

这对查询时的排序和比较非常重要,但不影响存储。

三、横向对比几种常见字符集

为了更直观地理解 utf8mb4,我们对比几种 MySQL 中常见的字符集:

字符集 最大字节数 支持范围 典型场景 是否支持 Emoji
latin1 1 字节 西欧字符(如英文) 老系统,纯英文存储 不支持
utf8 3 字节 Unicode BMP 基本多语言支持 不支持
utf8mb4 4 字节 完整 Unicode 国际化应用、Emoji 等 支持
ucs2 2 字节 Unicode BMP(固定长) 较少使用 不支持
  • latin1:非常老旧,适合纯英文场景,空间效率高,但不支持中文或 Emoji。
  • utf8:曾经是默认选择,但现在不推荐,因为它不支持 4 字节字符。
  • utf8mb4:现代应用的首选,几乎无短板。
  • ucs2:固定 2 字节编码,浪费空间且不支持扩展字符,已不常用。

四、如何存储 Emoji 等非纯粹文本信息?

如果你希望在数据库中存储 Emoji、生僻汉字或其他复杂字符,以下是具体建议:

1. 选择 utf8mb4 字符集

在表或字段级别明确指定:

sql 复制代码
CREATE TABLE users (
    `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''
);

或者在数据库级别设置默认字符集:

sql 复制代码
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

2. 检查 varchar 的长度

varchar(30) 表示最多存储 30 个字符,而不是 30 个字节。在 utf8mb4 中,一个字符可能占 1 到 4 个字节,所以实际存储的字节数可能是 30 到 120 字节。MySQL 会自动处理这一点,但你要确保长度足够容纳你的数据。

3. 客户端和连接配置

存储 Emoji 不只是数据库的事,客户端和连接也要支持 utf8mb4

  • 在 MySQL 配置文件(my.cnfmy.ini)中设置:

    ini 复制代码
    [client]
    default-character-set = utf8mb4
    
    [mysqld]
    character-set-server = utf8mb4
    collation-server = utf8mb4_0900_ai_ci
  • 连接数据库时,确保使用 utf8mb4 编码。例如在 PHP 中:

    php 复制代码
    $pdo = new PDO("mysql:host=localhost;dbname=mydb;charset=utf8mb4", "user", "pass");

4. 测试验证

插入一个 Emoji 测试一下:

sql 复制代码
INSERT INTO users (username) VALUES ('Alice 😊');
SELECT * FROM users;

如果显示正常,说明配置成功。

五、常见问题解答

1. utf8mb4 会不会占用更多空间?

理论上会,因为它支持 4 字节字符。但对于英文和汉字,实际占用字节数和 utf8 一样。只有当你存储 Emoji 等 4 字节字符时,才会多用空间。现代存储设备容量充足,这点开销通常可以忽略。

2. 为什么不直接用 utf8

如果你确定数据中不会有 4 字节字符(比如只存英文和中文),utf8 也没问题。但为了未来扩展性和兼容性,建议直接用 utf8mb4

六、总结

MySQL 的字符集选择看似复杂,其实核心就两条:

  • 需要存储 Emoji 或复杂字符?用 utf8mb4
  • 只存简单字符且追求历史兼容性?可以用 utf8latin1

对于现代应用,utf8mb4 是无可争议的首选。它不仅支持完整的 Unicode,还能轻松应对 Emoji 等新兴需求。只要正确配置数据库、字段和客户端连接,你就可以放心存储任何文本内容了。

相关推荐
用户67570498850230 分钟前
告别数据库瓶颈!用这个技巧让你的程序跑得飞快!
后端
千|寻1 小时前
【画江湖】langchain4j - Java1.8下spring boot集成ollama调用本地大模型之问道系列(第一问)
java·spring boot·后端·langchain
程序员岳焱1 小时前
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
后端·sql·mysql
龚思凯1 小时前
Node.js 模块导入语法变革全解析
后端·node.js
天行健的回响1 小时前
枚举在实际开发中的使用小Tips
后端
wuhunyu1 小时前
基于 langchain4j 的简易 RAG
后端
techzhi1 小时前
SeaweedFS S3 Spring Boot Starter
java·spring boot·后端
写bug写bug2 小时前
手把手教你使用JConsole
java·后端·程序员
苏三说技术2 小时前
给你1亿的Redis key,如何高效统计?
后端