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

news2024/11/13 10:09:20

前言

  本篇和大家一起深入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的拦截规则限制。

拉齐共识:回顾字符编码

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

ASCII

  ASCII(American 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字面量(literals)SQL中使用,如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对齐cs,即ci即不区分大小写,并且忽略变音,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一定推荐使用纯数字来进行,比如你的订单号、业务流水号等等,减少因为字符多样性带来的解释成本,不给差异留口子和存在空间,如果非要在使用字符串类型尽量保持统一大小写,不要再让重音(四种声调,甚至更多)、大小写(两种维度)等混淆数据,给系统带来不稳定的“坏味道”设计。

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/172532.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点

算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点 二叉搜索树的最近公共祖先 235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度…

第三章 逻辑与推理

命题逻辑谓词逻辑知识图谱推理因果推理 3.1 命题逻辑 逻辑和推理是基于知识的操作。 命题逻辑是应用一套形式化规则对以符号表示的描述性陈述进行推理的系统。在命题逻辑中,一个或真或假的描述性陈述被称为原子命题,对原子命题的内部结构不做任何解析。…

UnityC#的lock用法简记

UnityC#的lock用法简记简述代码实例一、单线程二、多线程无lock三、多线程使用lock死锁注意拓展lock->InvokeMonitor参考链接简述 多线程环境中,不使用lock锁,会形成竞争条件,导致错误。 使用lock锁可以保证当有线程操作某个共享资源时&a…

【ONE·C || 操作符详解】

总言 C语言:各种操作符的使用介绍。 文章目录总言1、算术操作符2、移位操作符2.1、整体介绍2.2、左移操作符2.3、右移操作符(逻辑右移、算术右移)3、位操作符3.1、整体介绍3.2、演示实例3.2.1、按位与3.2.2、按位或3.2.3、按位异或3.2.4、按位…

离线文章画像计算--Tfidf计算

2.4.2 Tfidf计算 2.4.2.1 目的 计算出每篇文章的词语的TFIDF结果用于抽取画像 2.4.2.2TFIDF模型的训练步骤 读取N篇文章数据文章数据进行分词处理TFIDF模型训练保存,spark使用count与idf进行计算利用模型计算N篇文章数据的TFIDF值 2.4.2.3 实现 想要用TFIDF进行…

【数据结构初阶(Java)】认识时间复杂度和空间复杂度

目录 前言: 1、算法效率 2、时间复杂度 1、大O的渐近表示法(不是一个准确的) 2、时间复杂度练习题(没有明确要求,计算的时间复杂度就是最坏情况下) 3、空间复杂度 前言: 如何衡量一个算法的…

Java中多线程wait和notify的用法

目录 一、wait和notify/notifyAll的由来 二、wait()方法 三、notify方法 3.1 notify的作用 3.2 wait和notify的 相互转换代码图 3.3 notifyAll 四、为什么需要notify和wait都需要上锁? 五、wait和sleep的对比 前言:由于线程之间是抢占式执行的&a…

Linux常用命令——tftp命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tftp 在本机和tftp服务器之间使用TFTP协议传输文件 补充说明 tftp命令用在本机和tftp服务器之间使用TFTP协议传输文件。 TFTP是用来下载远程文件的最简单网络协议,它其于UDP协议而实现。嵌入式linu…

RTMP协议封装H264和H265协议详解

RTMP协议封装H264和H265协议详解 文章目录RTMP协议封装H264和H265协议详解1 RTMP和FLV2 RTMP协议封装H264视频流2.1 RTMP发送AVC sequence header2.2 RTMP发送AVCC视频帧数据‘3 RTMP协议封装H265视频流1 RTMP和FLV 有关RTMP和FLV格式详细介绍可查看如下文章: http…

2022 Moonbeam的点点滴滴离不开社区支持

Moonbeam成为首个上线波卡的平行链已经有一周年🎂啦,这是一段疯狂的旅程🏍。 为了纪念这一时刻,我们通过公开数据来回顾这一年的众多里程碑、更新和整体发生的一切。 让我们来回顾一下Moonbeam在2022年取得了哪些成就吧。 &…

GIS二维电子地图开发总结

二维平面地图,目前支撑设备渲染,真实场景,后期电子围栏,运动轨迹等业务需求做铺垫 一、所涉及的技术栈: 1.Openlayers,加载渲染地图 2.Geoserver 发布wms和wfs()服务 3.Arcgis,Arcmap,进行源文件…

3.1、Ubuntu20桌面版远程连接SSHMobaXterm远程连接编辑器

连接SSH 安装系统完成并登陆后,输入 修改源码地址 进入apt文件夹 cd /etc/apt 备份文件 cp sources.list sources.list.bak 修改源码地址 vi sources.list # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of…

数据结构初级<排序>

本文已收录至《数据结构(C/C语言)》专栏! 作者:ARMCSKGT 你的阅读和理解将是我极大的动力! 目录 前言 排序的概念 常见排序简述 正文 直接插入排序 原理 代码实现 分析 希尔排序 原理 代码实现 分析 直接选择排序 原理 代码…

类加载的时机与过程

------ 摘自 周志明 《深入理解Java虚拟机》类加载的时机一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparati…

6、数组的常见运算

目录 一、数组的算术运算 二、数组的关系运算 三、数组的逻辑运算 一、数组的算术运算 (1)数组的加减运算:通过格式AB或A-B可实现数组的加减运算。但是运算规则要求数组A和B的维数相同。 示例1: A[1 2 3 4]B[2 4 6 8]C[1 1 …

三种简洁易行的方法解决基于Vue.js的组件通信

在总结Vue组件化编程的数据通信方面,看了网上的很多资料,都是讲父子组件的数据交互也就是参数传递,在组件的通信方面分几种情况,比如父子组件、非父子的兄弟组件、非父子的其他组件等等,这样看来,基于Vue.j…

STC15系列单片机EEPROM读写示例

STC15系列单片机EEPROM读写示例🌼STC15手册有关EEPROM描述 🌾STC15系列单片机内部集成了大容量的EEPROM,其与程序空间是分开的。利用ISP/IAP技术可将内部DataFlash当EEPROM,擦写次数在10万次以上。EEPROM可分为若干个扇区&#xf…

Android 蓝牙开发——蓝牙协议配置(七)

蓝牙主要分为两种模式,一种是媒体输出(Source)端,一种是媒体输入(Sink)端。也可以理解为服务端(Server)与客户端(Client)的关系。 蓝牙配置文件(B…

4-1指令系统-指令格式

文章目录一.指令的基本格式1.结构2.长度3.根据操作数地址码数目分类(1)零地址指令(2)一地址指令(3)二地址指令(4)三地址指令(5)四地址指令二.扩展操作码指令格…

Maven学习(二):Maven基础概念

Maven基础概念一、仓库二、坐标三、全局setting与用户setting区别一、仓库 仓库:用于存储资源,包含各种jar包;仓库分类: 本地仓库:自己电脑上的存储仓库,连接远程仓库获取资源;远程仓库&#x…