深入MySQL字符编码与对照规则

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

  本篇和大家一起深入MySQL的字符集与对照规则剖析下我们存储在MySQL中的字段是如何进行存储和校验比对的。

  • 先看问题unique key为什么失效了
  • 拉齐共识回顾下字符编码的基础知识回炉下ASCIIUnicode
  • 深入了解通过MySQL官网中对字符编码的支持和规则进行学习分析
  • 汇总结论根据掌握的规则来总结下项目实践中的注意事项

先看问题unique key为什么失效了

  最近做迁移数据的工作把A库数据迁移到B库中间没有任何处理逻辑是纯复制工作。但是在迁移过程中发现大部分表都可以正常完成迁移且源表和目标表数量能够保持一致只有两张表数据总是会少插入数据于是我开始按照以下思路排查

  • 第一步这两张有问题的表最大不同点是都有unique key其他的表没有猜测可能和此有关
  • 第二步发现两张表结构定义部分字段的字符集CHARACTER SET排序规则COLLATE不一致
  • 第三步带着上面两个差异点对比源表、目标表定位插入失败的数据缩小问题范围。

基于上述思路使用测试数据来阐述

  出现问题的表结构定义如下

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(32) NOT NULL COMMENT '姓名',
  `age` int(11) NOT NULL COMMENT '年龄',
  PRIMARY KEY (`id`), -- 主键
  UNIQUE KEY `name` (`name`,`age`) -- 联合唯一索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -- 表字符集

  插入一条数据如下

mysql> insert into user (name, age) value ('ZHANGSAN',1);

Query OK, 1 row affected (0.01 sec)

  随后再插入一条数据如下

mysql> insert into user (name, age) value ('zhangsan',1);

ERROR 1062 (23000): Duplicate entry 'zhangsan-1' for key 'name'

  这里两次插入name字段的值是大小写有区分的按照一般理解即使是相同字符但不同大小写的字符是不同的应该支持插入这里居然提示重复了命中了unique key的拦截规则限制。

拉齐共识回顾字符编码

推荐一个很不错的科普视频《快速搞懂🔍UnicodeASCIIUTF-8代码点编码…》

ASCII

  ASCIIAmerican Standard Code for Information Interchange美国信息交换标准代码是基于拉丁字母的一套电脑编码系统主要用于显示现代英语和其他西欧语言它是现今最通用的单字节编码系统。

image.png

  如上是一张ASCII码映射表它将西文字符映射到[0,127]之间的数字上即能够支持128个字符的表示。如果想要表示字符串Hello就会得到如下ASCII码映射

字符串十进制二进制
H720100 1000
e1010110 0101
l1080110 1100
l1080110 1100
o1110110 1111

  计算机存储是按照字节(Byte)来计算这里最大十进制数字是127它的二进制最多使用8位(Bit)表示因此最多ASCII编码消耗1个字节存储空间。

  ASCII编码在英文世界如鱼得水一切都井然有序但是世界语言还有很多中文、梵文、阿拉伯文等等ASCII编码对英文外的语言无法支持。

Unicode

这里有一个比较扣字眼的地方🤦‍♂️Unicode一般认为是字符集而具体的UTF8UTF16等认为是字符编码。

  • Unicode就是字典映射表码值管它叫字符集(Character Set)
  • UTF8就是转换二进制存储的方式管它叫编码(Encoding)

可以结合下文的编码规则差异品一品理解意思就好没必要背八股。

  基于上述我们需要更为通用、能够支持全世界多语种字符的编码来作为“通用语言”于是Unicode应运而生它能够囊括一百多种语言的十几万量级的字符其中包含重音符、表情符号和各种各样奇怪的特殊字符。

  关于Unicode的字符编码有以下特点

  • 「代码点映射」 在Unicode中字符需要首先映射到代码点(Code Points)上有的字符不止由一个代码点映射可以通过组合多个代码点组合来表示一个字符含义然后再通过得到的代码点转换成二进制来存储
    • Unicode支持的字符编码更丰富可包含数量大也能通过组合代码点来编码表示复杂符号dén、hören或表情👍🥺
    • ASCII被包含于Unicode中英文字母在Unicode中的代码点与ASCII中的映射值是一样的如unicode('H')的代码点、ascii('H')的映射值都是72
  • 「语言的存储差异」Unicode中代码点很多由于代码点排列分布的问题英文字符先入为主比较靠前是低位代码点因此转换成二进制的时候占用空间小而其他复杂语言的代码点“入场”较晚被安排在高位转换成二进制的时候空间占用就会大一些因此存储上其他语言相比英文字符来说会占用更多空间。

小结

编码规则差异

image.png

  • ASCII字符编码过程
    • [1] 根据字符找到唯一映射的ASCII码ascii('H') -> 72
    • [2] 根据ASCII码转换二进制进行存储如bin(ascii('H')) -> 0100 1000
  • Unicode字符编码过程
    • [1] 根据字符找到唯一映射的代码点(Code Point)unicode('H') -> 72
    • [2] 根据代码点(Code Point)转换二进制进行存储如bin(unicode('H')) -> 0100这里代码点的概念可以等同于ASCII的码值ASCII是一次映射得到值Unicode在此基础上还可以做组合之后映射。

image.png

  其实原理是类似的都需要预先做好一张字典表做映射实际存储的时候存的是字典映射表中的数字的二进制形式而已。Unicode更胜一筹的地方在于扩展了字典表规模容纳了更多的字符表达差异进来而且兼容了ASCII码已经定义的字典表直接进行了吸纳。

文本表达unicode编码表示
🔷��
🔶��

  而且Unicode打破了之前ASCII编码“一对一”映射的编码逻辑而是采用代码点的概念来做中间层转换将字典表映射编码规则进一步解耦支持组合多个代码点成为新的字符表示。然而这一切并不是没有代价的表示容量越大就意味着需要更多的数字而数字越大转换二进制的成本就越高下面展开讲。

空间占用对比

编码大小支持语言
ASCII1字节英文
Unicode2字节所有语言

  Unicode相比ASCII码会占用更多空间。

  • ASCII码的字典表词量有限支持需要支持英文主流语言和符号等最多只用一字节即可包括全部字符编码需求且具备一个特点就是字符数量等于字节数量即每个字符都只占一字节因此也就具备字符空间占用等长的特点。
  • Unicode代码点映射数字远远大于ASCII码的127这个数字2个字节空间可以支持16位的二进制存储映射到代码点的十进制数字能够容纳65535个这已经能够容纳非常庞大体量的文本映射表达能力了因此Unicode一般使用2字节即可生僻字或符号最多也不会超过4字节即可满足而且基于很多代码点还可以通过组合形成更大的字符表达。代码点和ASCII码值本质上都是一个十进制的数字因此范围越大且还要组合更大范围必然也需要更大的空间存储。

深入了解MySQL的字符编码

我们基于MySQL5.7来深入了解下MySQL中字符集相关内容的约定、规则和支持官方文档关于这部分内容的介绍 Character Sets, Collations, Unicode中文对照

字符集、对照规则

基础概念

  先来认识下MySQL中我们创建库、表常用到的两个关键词character setcollate

关键词含义作用支持配置级别
character set字符集文本编码方式服务器
数据库

collate校验、对照规则文本对照的规则用于对比一致性、差异性等在条件查询匹配数据库防重幂校验等都会用到服务器
数据库

  下面是一些character setcollate的特点

  • 「支持级别」MySQL中字符集和对照规则有四个级别的默认设置服务器Server数据库database表table列column此外也支持SQL级别的字面量literals编码、对照能力。
  • 「规则关系」 不同层级之间采用“最近原则”进行覆盖举例若字段级别配置声明了编码和对照规则则字段使用该规则否则会使用就近的表一级配置以此类推到数据库、服务器级别。

参数配置

  下面来看下字符编码、对照规则的各级别配置的方式和参数配置

级别编码参数对照参数
服务器(server)character_set_servercollation_server
数据库(database)character_set_databasecollation_database
表(table)建表语句 Table CHARSET建表语句 Table COLLATE
字段(column)建表语句 Column CHARSET建表语句 Column COLLATE
SQL字面量literalsSQL中使用如SELECT * from test where col_1= _utf8mb4'aaa' COLLATE utf8mb4_bin;同左

  除此之外还支持一些其他方式的编码干预影响策略可以通过show variables like '%character_set_%'命令来查看和扩展如存储编码可以和最终展示的编码方式可以进行转换或兼容此处不做展开感兴趣可以根据上方官网链接进行扩展尝试。

字符集库

字符集的支持

参考 MySQL支持的字符集和排序规则

  MySQL字符集库支持非常广泛总的来说一般常用的字符集都是Unicode的子集只有个别领域、足够小众的字符集才需要考虑兼容等棘手却又不太可能发生的场景问题因此对于使用MySQL的用户来说不太会存在这种“海纳百川唯漏一斗”的尴尬。

字符集的选择

  通过综上对字符编码的回顾和论述我们能够明白一件事选择什么样的字符集就意味着使用什么样的字符支持能力以及编码规则所以我们在选择字符集的时候需要考虑的主要有

  • [1] Q字符集是否能够支持业务存储的大部分文本

      一般来说国内大部分业务除了汉字、英文、数字、符号基本没有其他特别需要考虑的场景因此只要支持以上文本编码即可。
  • [2] Q存储空间的消耗如何

      只有全高位的字符映射理论上会相对占用很多存储空间否则不需要过分关心按照字符编码必不可少的“沉默成本”来对待即可。
  • [3] Q性能如何

      可能你会疑惑了为什么还有性能问题呢匹配查询、内容对比是一个高频场景功能它受到内容存储形态的影响尤其是面对大数据体量的样本匹配、对比会有很大影响这个后面我们会展开讲到。

  一般来说utf8及其扩展字符集是最常用的常见的家族表列举如下

字符集描述每个字符占用空间基本多语言平面(BMP)字符、补充字符的支持
utf8Unicode字符集的UTF-8编码别名utf8mb31~3字节仅支持 BMP 字符
utf8mb4Unicode字符集的UTF-8编码1~4字节支持
utf16Unicode字符集的UTF-16编码2~4字节支持
utf32Unicode字符集的UTF-32编码4字节支持

如果你疑惑什么是BMP可以参考 BMP基本多语音平面的概念。

  下面通过一个例子验证下首先创建一张表分别配置字段的字符编码col_1utf8mb4col_2utf8如下

CREATE TABLE `test` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `col_1` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
  `col_2` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

  然后分别给两个字段插入“😄”这个表情来看看

小提示 如果使用命令行交互可以先执行如下命令保持连接会话使用utf8mb4编码进行数据传输避免不兼容一般MySQL图形工具都默认支持。


mysql> SET NAMES utf8mb4;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into test (col_1) value ('😄');
Query OK, 1 row affected (0.03 sec)

mysql> insert into test (col_2) value ("😄");
ERROR 1366 (HY000): Incorrect string value: '\xF0\x9F\x98\x84' for column 'col_2' at row 1

  显然utf8(即utf8mb3)对类似字符是不支持的无法完成这种符号的编码存储和插入而utf8mb4支持虽然utf16utf32也支持但是能看到它们的编码空间上存在一些“浪费”所以在一般系统设计中对字符串字段存储选择utf8mb4是比较通用和推荐的。

元数据使用UTF-8字符集

  MySQL中的自身元数据选择使用UTF-8字符集来提供交互这点不言而喻了它能提供标准字符集范围可以兼容所有子集而且一般都是英文绝对可以满足所有场景没有后顾之优。

字符集的命名规则

参考 MySQL字符集命名规则

  命名规则是按照"encoding_feature_collate"的结构来定位和区分的。

  • encoding即字符编码集如utf8
  • feature即字符特征如general是通用的turkish是面向土耳其语的
  • collate即对比校验规则如是否区分大小写、重音符号是否敏感
命名后缀含义举例
_aiAccent-insensitive变音不敏感ǎà认为是相同字符
_asAccent-sensitive变音敏感ǎà认为是不同字符
_ciCase-insensitive大小写不敏感Aa认为是相同字符
_csCase-sensitive大小写敏感Aa认为是不同字符
_binBinary基于二进制判断

  下面是一些命名后缀的特点

  • 「规则关系」 如果没有声明重音规则后缀则按照大小写规则后缀进行统一_ai对齐ci,_as对齐csci即不区分大小写并且忽略变音cs则即区分大小写也区分变音。
  • 「二进制对照」 bin区别于以上是独立的一种对照规则。
分类字段类型对比规则
二进制字符串binary、varbinary、blob基于数字字节值进行排序、对比
非二进制字符串char、varchar、text、longtext基于数字字节值进行排序、对比
基于字符序列、多序列进行排序、对比

字符集的对照规则

  下面用例子验证下不同对照规则。首先创建一张表让字段编码类型和校验格式分别能够支持*_ci*_cs*_bin如下

CREATE TABLE `test` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `col_1` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
  `col_2` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci, 
  `col_3` varchar(50) CHARACTER SET latin7 COLLATE latin7_general_cs,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1

  插入两条大小写数据方便验证。

mysql> insert into test (col_1,col_2,col_3) value ('A','A','A');
Query OK, 1 row affected (0.03 sec)
mysql> insert into test (col_1,col_2,col_3) value ('a','a','a');
Query OK, 1 row affected (0.03 sec)
mysql> select * from test;
+----+-------+-------+-------+
| id | col_1 | col_2 | col_3 |
+----+-------+-------+-------+
|  1 | A     | A     | A     |
|  2 | a     | a     | a     |
+----+-------+-------+-------+
2 rows in set (0.00 sec)

  分别对三个不同字符编码的字段用同一个条件进行查询验证如下

-- utf8mb4_bin

mysql> SELECT * from test where col_1= 'A';
+----+-------+-------+-------+
| id | col_1 | col_2 | col_3 |
+----+-------+-------+-------+
|  1 | A     | A     | A     |
+----+-------+-------+-------+
1 row in set (0.00 sec)

-- utf8mb4_general_ci

mysql> SELECT * from test where col_2= 'A';
+----+-------+-------+-------+
| id | col_1 | col_2 | col_3 |
+----+-------+-------+-------+
|  1 | A     | A     | A     |
|  2 | a     | a     | a     |
+----+-------+-------+-------+
2 rows in set (0.01 sec)

-- latin7_general_cs

mysql> SELECT * from test where col_3= 'A';
+----+-------+-------+-------+
| id | col_1 | col_2 | col_3 |
+----+-------+-------+-------+
|  1 | A     | A     | A     |
+----+-------+-------+-------+
1 row in set (0.00 sec)

  将结果汇总如下

  • *_ci是大小写不敏感的无论输入a还是A都会把aA数据查询出来
  • *_cs是大小写敏感的输入a就匹配a输入A就匹配A
  • *_bin是大小写敏感的输入a就匹配a输入A就匹配A

二进制与字符串的对照差异

  最后再来对比下二进制存储字符串存储的区别再来创建一张表分别将字段设置为二进制字符串格式

CREATE TABLE `test` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `col_1` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
  `col_2` blob COLLATE `binary`,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1

  插入数据

mysql> insert into test (col_1,col_2) value ('A','A');
Query OK, 1 row affected (0.02 sec)

mysql> insert into test (col_1,col_2) value ('a','a');
Query OK, 1 row affected (0.02 sec)

mysql> select * from test;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | A     | A     |
|  2 | a     | a     |
+----+-------+-------+
2 rows in set (0.00 sec)

  保持同一个条件完成查询

-- varchar collate utf8mb4_bin

mysql> select * from test where col_1='A';
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | A     | A     |
+----+-------+-------+
1 row in set (0.00 sec)

-- blob collate binary 

mysql> select * from test where col_2='A';
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | A     | A     |
+----+-------+-------+
1 row in set (0.00 sec)

  得到结论是二者都是基于二进制做对照是大小写敏感的等同于*_cs后缀对照规则。下面我们通过SQL的字面量来强制改变下字符对照规则来看看

-- varchar collate utf8mb4_general_ci 使用大小写不敏感来查询
mysql> select * from test where col_1='A' collate utf8mb4_general_ci;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | A     | A     |
|  2 | a     | a     |
+----+-------+-------+
2 rows in set (0.00 sec)

-- blob collate utf8mb4_general_ci 使用大小写不敏感来查询

mysql> select * from test where col_2='A' collate utf8mb4_general_ci;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | A     | A     |
|  2 | a     | a     |
+----+-------+-------+
2 rows in set (0.00 sec)

  可以看到传入*_ci后缀对照规则后大小写不敏感了可全部查询出来。二进制存储字符串存储都支持对照规则的“就近传入”来影响最终查询的数据输出。

  尾随空间处理“陷阱” 需要特别注意。对于非二进制的字符串编码会默认存储所有的空格空间但是在匹配对照时会剔除尾随空格。

  先来插入测试数据如下

mysql> insert into test (col_1) value ('a');
Query OK, 1 row affected (0.02 sec)

mysql> insert into test (col_1) value ('a ');
Query OK, 1 row affected (0.04 sec)

mysql> insert into test (col_1) value (' a ');
Query OK, 1 row affected (0.02 sec)

mysql> select *,length(col_1) from test;
+----+-------+---------------+
| id | col_1 | length(col_1) |
+----+-------+---------------+
|  4 | a     |             1 |
|  5 | a     |             2 |
|  6 |  a    |             3 |
+----+-------+---------------+
3 rows in set (0.00 sec)

  接着进行查询仔细观察检索条件和匹配结果如下

mysql> select * from test where col_1='a';
+----+-------+
| id | col_1 |
+----+-------+
|  4 | a     |
|  5 | a     |
+----+-------+
2 rows in set (0.00 sec)

mysql> select * from test where col_1='a ';
+----+-------+
| id | col_1 |
+----+-------+
|  4 | a     |
|  5 | a     |
+----+-------+
2 rows in set (0.00 sec)

mysql> select * from test where col_1=' a';
+----+-------+
| id | col_1 |
+----+-------+
|  6 |  a    |
+----+-------+
1 row in set (0.00 sec)

mysql> select * from test where col_1=' a ';
+----+-------+
| id | col_1 |
+----+-------+
|  6 |  a    |
+----+-------+
1 row in set (0.00 sec)

  不难发现匹配默认剔除了尾随空格再来看看二进制存储的情况先插入表数据:

mysql> insert into test(col_2) value('a');
Query OK, 1 row affected (0.03 sec)

mysql> insert into test(col_2) value('a ');
Query OK, 1 row affected (0.02 sec)

mysql> insert into test(col_2) value(' a ');
Query OK, 1 row affected (0.03 sec)

mysql> select *,length(col_2) from test;
+----+-------+-------+---------------+
| id | col_1 | col_2 | length(col_2) |
+----+-------+-------+---------------+
|  1 | NULL  | a     |             1 |
|  2 | NULL  | a     |             2 |
|  3 | NULL  |  a    |             3 |
+----+-------+-------+---------------+
3 rows in set (0.00 sec)

  再来查询下看看匹配结果

mysql> select * from test where col_2 ='a';
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | NULL  | a     |
+----+-------+-------+
1 row in set (0.00 sec)

mysql> select * from test where col_2 ='a ';
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  2 | NULL  | a     |
+----+-------+-------+
1 row in set (0.00 sec)

mysql> select * from test where col_2 =' a ';
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  3 | NULL  |  a    |
+----+-------+-------+
1 row in set (0.00 sec)

mysql> select * from test where col_2 =' a';
Empty set (0.00 sec)

  二进制存储的字段才是真正“秉持Geek精神”的存储什么就匹配什么没有丝毫的默认夹带处理。

  基于上述要区分二者的区别根据需要进行适配设计。

汇总结论掌握规则避免踩坑

  综上我们已经较为细致地回顾了ASCIIUnicode两种字符编码以及MySQL中对字符集、字符编码、对照规则的定义、分类、使用等下面做个整体总结。

对存储的影响

  直接用SQL来查看即可_utf8mb4是相对来说空间性价比最高覆盖字符表达映射最强的。

mysql> select length(_utf8mb3'H'),length(_utf8mb4'H'),length(_utf16'H'),length(_utf32'H');
+---------------------+---------------------+-------------------+-------------------+
| length(_utf8mb3'H') | length(_utf8mb4'H') | length(_utf16'H') | length(_utf32'H') |
+---------------------+---------------------+-------------------+-------------------+
|                   1 |                   1 |                 2 |                 4 |
+---------------------+---------------------+-------------------+-------------------+
1 row in set (0.00 sec)

对Unique Key的影响

  创建一张表配置两个字段分别为*_ci*_bin并设置字段为唯一索引进行防重设计如下

CREATE TABLE `test` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `col_1` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
  `col_2` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  PRIMARY KEY (`id`),
  unique key (`col_1`),
  unique key (`col_2`)
) ENGINE=InnoDB AUTO_INCREMENT=1

  先插入底表数据如下

mysql> insert into test (col_1,col_2) value ('a','a');
Query OK, 1 row affected (0.02 sec)

mysql> select * from test;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | a     | a     |
+----+-------+-------+
1 row in set (0.00 sec)

  下面进行大小写做撞库测试

-- 先对大小写敏感的唯一索引进行插入测试只要字符相同大小写不同就可以插入

mysql> insert into test (col_1) value ('a');
ERROR 1062 (23000): Duplicate entry 'a' for key 'col_1'
mysql> insert into test (col_1) value ('A');
Query OK, 1 row affected (0.02 sec)

-- 再对大小写不敏感的唯一索引进行插入测试只要字符相同就不可以插入

mysql> insert into test (col_2) value ('a');
ERROR 1062 (23000): Duplicate entry 'a' for key 'col_2'
mysql> insert into test (col_2) value ('A');
ERROR 1062 (23000): Duplicate entry 'A' for key 'col_2'

  结果一目了然整理如下

分类防重效果业务场景
区分大小写只要字符相同大小写不同就可以插入适合字符维度+大小写维度的联合防重不会误杀能多支持一些信息填入
不区分大小写只要字符相同就不可以插入适合字符维度不区分大小写的防重严格准入

  最后建议大家使用数据库的unique key一定推荐使用纯数字来进行比如你的订单号、业务流水号等等减少因为字符多样性带来的解释成本不给差异留口子和存在空间如果非要在使用字符串类型尽量保持统一大小写不要再让重音(四种声调甚至更多)、大小写(两种维度)等混淆数据给系统带来不稳定的“坏味道”设计。

亲爱的朋友感谢你读到最后希望本文对你有帮助~🫰

欢迎点赞、收藏、关注一键三连支持~❤️

我会继续坚持输出高质量文章分享~💪

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: mysql

“深入MySQL字符编码与对照规则” 的相关文章