距离上次发稿 已经过去好久了,
开搞,2023第一稿;
.还原问题现场
前段时间,为了防止商品组产生重复的数据,我专门加了一张防重表。
问题就出在商品组的防重表上。
具体表结构如下:
为了保证数据的唯一性,我给那种商品组防重表,建了唯一索引:
根据分类编号、单位编号和商品组属性的 hash 值,可以唯一确定一个商品组。
给商品组防重表创建了唯一索引之后,第二天查看数据,发现该表中竟然产生了重复的数据:
表中第二条数据和第三条数据重复了。
这是为什么呢?
2.唯一索引字段包含 null
如果你仔细查看表中的数据,会发现其中一个比较特殊地方:商品组属性的 hash 值(model_hash 字段)可能为null,即商品组允许不配置任何属性。
在 product_group_unique 表中插入了一条 model_hash 字段等于 100 的重复数据:
从上图中看出,mysql 的唯一性约束生效了,重复数据被拦截了。
接下来,我们再插入两条 model_hash 为 null 的数据,其中第三条数据跟第二条数据中 category_id、unit_id 和 model_hash 字段值都一样。
从图中看出,竟然执行成功了。
换句话说,如果唯一索引的字段中,出现了 null 值,则唯一性约束不会生效。
最终插入的数据情况是这样的:
当 model_hash 字段不为空时,不会产生重复的数据。
当 model_hash 字段为空时,会生成重复的数据。
我们需要特别注意:创建唯一索引的字段,都不能允许为 null,否则 mysql 的唯一性约束可能会失效。
下面的几种不同方案 点击文末跳转原文,这几种思路在不同的业务场景还是值得学习的。
3.逻辑删除表加唯一索引
3.1 删除状态 +1
3.2 增加时间戳字段
3.3 增加 id 字段
- 重复历史数据如何加唯一索引?
5.给大字段加唯一索引
5.1 增加 hash 字段
5.2 不加唯一索引
5.3 redis 分布式锁
6.批量插入数据