解决mysql存储emoji表情唯一索引报错问题

问题发现:

1、正常上班的一天,突然间有运营同事反馈,我们在添加数据的时候,发现添加了之后,对应的没有了,添加了然后就没有了,需要研发帮忙分析一下为什么。

原因分析:

1、从运营的反馈我第一印象应该是前端搞错了,把本应该调用新增的接口调错成了修改接口,于是让前端先排查,前端反馈新增和修改是同一个接口,这着实让我心头一紧,咋回事?程序BUG了?

2、一通排查一下了,程序并没有发现什么问题,可为什么会被替换了?只能继续向后排查,那就到了MySQL了。我们使用的是INSERT INTO ON DUPLICATE KEY UPDATE,针对该字段使用了唯一索引,如果发现存在相同的值就直接替换掉,建表语句如下:

CREATE TABLE `du_test` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`tt` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `tt` (`tt`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4
;

3、当我们插入了以后,再插入一下,就会报唯一键冲突错误:

解决mysql存储emoji表情唯一索引报错问题_第1张图片

 4、明明和是不同的字符,单独存储也都没有问题,可为什么在唯一键验证的时候,会报冲突的错误的,这个时候突然间想起来了字符集的比较规则,也就是MySQL的关键字:

COLLATE='utf8mb4_general_ci'

utf8mb4 默认排序规则是utf8mb4_general_ci,它只区分 BMP 字符,而我们的emoji字符其实不在这个范围内的,也就是唯一索引校验的时候,根本就不会对带上emoji字符,知道原因之后,那就需要找一种能处理emoji字符的比较规则。

解决方案:

1、_bin的比较规则是怎么比较的?

二进制字符串是字节序列。对于binary collation,比较和排序基于字节数字值。非二进制字符串(CHAR, VARCHAR,TEXT )是字符序列,可能是多字节的。非二进制字符串的比较规则定义了用于比较和排序的字符值的顺序。对于_bin collation,这种排序基于字符代码数字值,这与二进制字符串的排序类似,只是字符代码值可能是多字节的。

2、修改原来的字段的字符集为utf8mb4_bin,问题解决

CREATE TABLE `du_test_1` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`tt` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_bin',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `tt` (`tt`) USING BTREE
)
COMMENT='名单操作历史表'
COLLATE='utf8mb4_bin'
ENGINE=InnoDB
AUTO_INCREMENT=8
;

3、测试:

解决mysql存储emoji表情唯一索引报错问题_第2张图片

 从上图可以看到,和都正常插入进去了。

最后:

很多文档或者工具把MySQL的COLLATE翻译成排序规则,我认为稍微有点欠妥,或者说不够直观,其实它的英文是“perform comparisons according to a variety of collations”,翻译成比较规则更合适一些,需要排序的场景肯定需要比较,需要比较的场景不一定需要排序。

你可能感兴趣的:(mysql,mysql,emoji,UNIQUE,COLLATE,utf8mb4_bin)