在MySQL数据库开发过程中,字符集和排序规则是大家经常碰到的配置要点。比如说在定义字段的时候,可能会看到这样的语句:

`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-8、UTF-16和UTF-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(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
latin11字节西欧字符(如英文)老系统,纯英文存储场景不支持
utf83字节Unicode BMP适用于基本多语言支持场景不支持
utf8mb44字节完整Unicode国际化应用,以及需要存储Emoji等复杂字符的场景支持
ucs22字节Unicode BMP(固定长)较少使用不支持
  • latin1:这个字符集比较老旧了,只适合纯英文的存储场景,虽然空间利用效率高,但没办法支持中文和Emoji。
  • utf8:以前它是默认选择,但现在不太推荐了,主要是它不支持4字节字符。
  • utf8mb4:对于现代应用来说,它基本没什么明显缺点,是比较理想的选择。
  • ucs2:采用固定2字节编码,不仅浪费空间,还不支持扩展字符,现在已经很少用了。

四、存储Emoji等特殊字符的方法

要是想在数据库里存储Emoji、生僻汉字这类复杂字符,可以参考下面这些建议:

选择utf8mb4字符集

可以在表或者字段级别指定字符集,比如:

CREATE TABLE users ( `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' ); 

也能在数据库级别设置默认字符集:

CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; 

检查varchar的长度

varchar(30)表示最多能存储30个字符,而不是30个字节。在utf8mb4字符集中,一个字符可能占用1 – 4个字节,所以实际存储的字节数可能在30 – 120字节之间。MySQL会自动处理这些,但你得确保设置的长度足够存储你的数据。

客户端和连接配置

存储Emoji可不只是数据库单方面的事,客户端和连接也得支持utf8mb4

  • 在MySQL配置文件(my.cnfmy.ini)里进行如下设置:
[client] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_0900_ai_ci 
  • 以PHP为例,连接数据库时要确保使用utf8mb4编码:
$pdo = new PDO("mysql:host=localhost;dbname=mydb;charset=utf8mb4", "user", "pass"); 

测试验证

配置好之后,可以插入一个Emoji进行测试:

INSERT INTO users (username) VALUES ('Alice 😊'); SELECT * FROM users; 

要是显示正常,那就说明配置成功了。

五、常见问题解答

utf8mb4会不会占用更多空间?

从理论上来说,会有这种情况,毕竟它支持4字节字符。不过对于英文和汉字,utf8mb4实际占用的字节数和utf8是一样的。只有在存储像Emoji这类4字节字符时,才会多占用一些空间。但现在存储设备的容量都比较大,这点额外的开销通常可以忽略不计。

为什么不直接用utf8?

如果能确定数据里不会出现4字节字符,比如只存英文和中文,用utf8也没问题。但从未来的扩展性和兼容性考虑,还是建议直接使用utf8mb4

六、总结

MySQL字符集的选择看着复杂,其实关键就两点:

  • 要是需要存储Emoji或其他复杂字符,那就选utf8mb4
  • 要是只存简单字符,并且追求历史兼容性,utf8latin1也可以考虑。

对于当下的应用开发,utf8mb4无疑是最佳选择。它不仅支持完整的Unicode,还能轻松应对Emoji等新需求。只要把数据库、字段和客户端连接都配置正确,就不用担心文本存储的问题了。