摘要:字符集是一套符号和编码。校对规则是在字符集内用于比较字符的一套规则。

本文分享自华为云社区《一个字符校对规则引发的血案》,原文作者:DRS技术快客 。

问题现场

我们先看一个建表语句

CREATE TABLE collate_test (
val1 char(32) COLLATE utf8mb4_general_ci,
val2 char(32)
) CHARACTER SET utf8mb4;

当我们在MySQL5.7和MySQL8.0上建表,都能建成功,但是当建成功之后,我们都执行SQL:SELECT * FROM collate_test WHERE val1=val2的时候:
在5.7上执行

mysql> SELECT * FROM collate_test WHERE val1=val2;
Empty set (0.00 sec)

在8.0上执行

mysql> SELECT * FROM collate_test WHERE val1=val2;
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '='

很奇怪,为什么会出现utf8mb4_0900_ai_ci呢?

我们查看MySQL的资料https://dev.mysql.com/doc/refman/8.0/en/charset-mysql.html 发现,原来MySQL8.0在UTF8mb4字符集下面的默认排序规则为utf8mb4_0900_ai_ci

现场分析

然后我们再分别来看一下建表语句:SHOW CREATE TABLE collate_test
在5.7上执行

 show create table collate_test;
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+
| Table        | Create Table                                                                                                                         |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+
| collate_test | CREATE TABLE `collate_test` (`val1` char(32) DEFAULT NULL,`val2` char(32) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+

在8.0上执行

show create table collate_test;
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+
| Table        | Create Table                                                                                                                         |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+
| collate_test | CREATE TABLE `collate_test` (`val1` char(32) DEFAULT NULL,`val2` char(32) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------+

看出来差别了,8.0上建表的时候,被加上了collate属性
在8.0执行

mysql> SHOW CHARACTER SET WHERE Charset="utf8mb4";
+---------+---------------+--------------------+--------+
| Charset | Description   | Default collation  | Maxlen |
+---------+---------------+--------------------+--------+
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci |      4 |
+---------+---------------+--------------------+--------+
1 row in set (0.01 sec)

原来8.0中建表的时候,当指定字符集为utf8mb4的时候,它的默认collation就是utf8mb4_0900_ai_ci,而mysql不允许两个互斥的校验规则的数据做对比,而utf8mb4_0900_ai_ci与utf8mb4_general_ci是互斥的

扩展问题

这里面问题比较简单,因为一般我们不会对同一个表的不同字段设置相同字符集不同校对规则,但是在不同的表结构之前,我们有可能不经意之间就犯了这个错误,例如,联表,触发器等。

联表查询

比如下面两个表

CREATE TABLE collate_general(
val1 char(32)
) COLLATE utf8mb4_general_ci;CREATE TABLE collate_0900 (
val2 char(32)
) COLLATE utf8mb4_0900_ai_ci;

当我们联表查询的时候

mysql> select * from collate_general,collate_0900 where val1=val2;
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '='

触发器

比如我们先建一个表和触发器(为举例需要,触发器并无实际意义)

CREATE TABLE collate_trigger(
val1 char(32)
) COLLATE utf8mb4_general_ci;DELIMITER ||
CREATE TRIGGER trigger_0900 AFTER INSERT ON collate_trigger FOR EACH ROW
BEGINDECLARE val2 VARCHAR(32);SET val2=new.val1;SELECT val1 into val2 from collate_trigger WHERE val1=val2;
END||
DELIMITER ;

当我们向表中插入数据的时候

mysql> insert into collate_trigger values ('abc');
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '='

然后我们看一下建表语句

mysql> show create table collate_trigger;
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table           | Create Table                                                                                                                                                  |
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| collate_trigger | CREATE TABLE `collate_trigger` (`val1` char(32) COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci |
+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+

我们再看一下触发器

mysql> show create trigger trigger_0900\G
*************************** 1. row ***************************Trigger: trigger_0900sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
SQL Original Statement: CREATE DEFINER=`root`@`localhost` TRIGGER `trigger_0900` AFTER INSERT ON `collate_trigger` FOR EACH ROW BEGINDECLARE val2 VARCHAR(32);SET val2=new.val1;SELECT val1 into val2 from collate_trigger WHERE val1=val2;
ENDcharacter_set_client: gbkcollation_connection: gbk_chinese_ciDatabase Collation: utf8mb4_0900_ai_ciCreated: 2021-05-31 15:24:44.40

发现没有,触发器的Database collation为utf8mb4_0900_ai_ci,在触发器的比较语句中,val1为collate_trigger的字段,collation为utf8mb4_general_ci,val2为触发器trigger_0900的自有字段,collation为utf8mb4_0900_ai_ci。

本文中举例都比较简单直接,客户真实业务场景可能都比较复杂,但是所遇问题的原因都是一样的。由此可见,在处理MySQL之前的版本升级到8.0版本的时候,字符集校验规则一定要注意了

点击关注,第一时间了解华为云新鲜技术~

因为一个字符校对问题,我的大厂面试挂了相关推荐

  1. 谷歌程序员犯低级错误?少打一个字符引发重大 Bug,致大量 Chromebook 无法解锁...

    整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 初学编程的程序员难免会犯一些低级错误,这不难理解. 可当这种低级错误出现在谷歌经过三个开发者版本进而推出的 Chrome OS 正式版中 ...

  2. 字符常量和仅包含一个字符的字符串之间的区别

    'x'与"x"是不同的,前者是一个整数,其值是字母x在机器字符集中对应的数值(内部表示值),后者是一个包含一个字符(即字母x)以及一个结束符'\0'的字符数组.

  3. php去掉字符串的最后一个字符 substr()的用法

    今天项目中用到,去掉字符串中的最后一个字符 原字符串1,2,3,4,5,6, 去掉最后一个字符",",最终结果为1,2,3,4,5,6 代码如下: $str = "1,2 ...

  4. java字符存储_用java的类集框架做一个字符存储器(15)

    11.这是java的关于java的类集框架做一个字符存储器的源代码可以直接进行编译运行,希望大家能够从中获益良多. package niming; //导入ArrayList这个类 import ja ...

  5. [Linux]从控制台一次读取一个字符,无需等待回车键

    [Linux]从控制台一次读取一个字符,无需等待回车键 周银辉 读取字符嘛,可以使用getchar(),getch()等等函数,但它们都需要等待回车键以结束输入,而不是按下键盘时立即响应,看上去不那么 ...

  6. Java:判断一个字符串中是否存在另一个字符子串以及判断一个字符串中是否存在指定字符

    Java:判断一个字符串中包含指定字符子串,判断一个字符串中存在指定字符 字符串的contains方法可以判断一个字符串中是否存在另一个字符子串,示例如下 String Str = "Hel ...

  7. php 正则 最后一个字符,关于正则表达式:在PHP中查找字符串中的最后一个字符...

    我正在用PHP进行一些URL重写,需要找到末尾有斜线的URL,然后执行301重定向.我以为会有一个简单的PHP函数来查找最后一个字符串,但我找不到任何东西.第一直觉让我觉得我需要使用regex,但我不 ...

  8. html判断数字数据的大小写,判断一个字符是否是数字、还是大小写字母

    //方法一: int main() { printf("please input one character:\n");         input=getchar(); whil ...

  9. python中如何判断输入的是英文字母_python如何判断一个字符是否为汉字,英文字母,数字,空还是其他...

    一直在忙工作的事情,对不起大家,今后一定抽出时间来写python,和大家一起学python. 今天给大家一段代码,大家可以看一下哈. # 判断一个字符是否为汉字,英文字母,数字,空还是其他 # 使用U ...

最新文章

  1. 计算机组成原理中的“上溢”和“下溢”分别的定义是什么?
  2. Ionic 2.0 相关资料
  3. 黑客使用一个UDP数据包可以打开任何HID门禁控制器
  4. TFS2018环境搭建一硬件要求
  5. 用python发邮件为什么接收不了_如何使用python发送邮件和接收邮件?
  6. ictclas4j java_ictclas4j 分词工具包 安装流程
  7. iphone怎么连接itunes相关解锁教程
  8. java web开发常见问题_javaWeb开发中常见的问题
  9. scanf_s()函数的用法
  10. WiFi beacon时槽
  11. Ubuntu安装百度云盘
  12. proc oracle12c,Oracle12cRAC安装遭遇CLSRSC-507: The root script cannot proceed on this node
  13. 瑞星2008公开测试 下载试用,还有奖品!
  14. ggbiplot | 带箭头的主成分分析(PCA)图绘制
  15. 设备树学习(二、设备树dts/dtsi格式)
  16. SF21 | 利用PSY指标,我们来开发一个短线模型?
  17. 抗衰老产品nmn,nmn纯度越高越好吗,揭秘nmn的老底
  18. Android开发 —— apk打包流程
  19. Android---隐藏通话界面手机号码显示
  20. 计及源荷不确定性的综合能源生产单元运行调度与容量配置优化研究(Matlab代码实现)

热门文章

  1. 安装Bootstrap3编译版本
  2. es6 yield表达式
  3. scheduledexecutorservice 只执行一次_一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考...
  4. 1067 mysql,mysql免安装版1067错误终极解决办法图文教程
  5. curl txt批量_curl与wget高级用法
  6. dubbo provider异步_Dubbo相关面试题
  7. 大话西游2服务器维护,大话西游2:9.10维护解读:灵犀调整全服上线,去疾调整是好是坏?...
  8. bootstraptable设置行高度_【短柱专题】窗台板为什么要通长设置
  9. 2019-05-22 防范ASP木马;如何防止注入攻击;
  10. 【luogu P3627 [APIO2009]抢掠计划】 题解