保持 Unique Key 的逻辑删除方案
前言
实际开发中,重要的业务数据一般不回使用物理删除,都是使用一个状态标记 deleted 实现逻辑删除,但这种情况下会破坏唯一索引。
再往唯一约束列插入相同的值时,会报 Duplicate Entry,但在业务上该值是必须要插入的。
下面我们聊聊如何保持唯一索引
解决方案
方案一:使用物理删除
方案二: 新建历史/备份表
每次删除时,主表进行物理删除,同时将删除的记录保存到历史/备份表中
方案三: 多 deleted 值
deleted
:0
代表未删除,其他值代表删除
id | user_id | name | deleted |
1 | 1 | Edward | 0 |
2 | 1 | Edward | 1 |
3 | 1 | Edward | 2 |
这种方式可以保持 Unique Key
,但在 deleted 冲突比较多,需要保证 deleted 累加。
- deleted: 0 代表未删除,删除时把 deleted 赋值为时间戳
UNIX_TIMESTAMP(NOW())
。将删除状态和之前的唯一约束 A 重新组成唯一联合索引 index(A、deleted)
这种方式的好处除了可以保证唯一索引还可以知道删除的时间,但是对于历史数据涉及到修改业务。
方案四:取消表的唯一约束,同时引入 redis 来保证唯一约束
取消表的唯一性约束,项目中引入 redis ,通过 redis 来判重,新增时向 redis 中 set 记录,删除时,删除 redis 记录。
缺点:增加了系统复杂度,同时需要保证 reids 和数据库的一致性。
方案五:保留删除标记,同时新建一个字段 del_unique_key
保留删除状态位,再新增一个字段 del_unique_key
,默认值为0,字段的类型和大小与主键 id 保持一致,同时与原先的唯一约束重新组成联合唯一约束 index(A,del_unique_key)
。进行逻辑删除时,将 del_unique_key
值改为 该删除行的主键Id。
方案取舍
方案一需要从实际业务上考虑,如果物理删除队业务无损,那就无所谓了。
方案二需要额外新增一张记录表,如果只是用来实现记录删除,有点大材小用了。
方案四引入redis,可以解决问题,但增加了系统复杂度,同时需要保证 reids 和数据库的一致性。
方案三和方案五四路其实是一样的,如果是对已经上线的项目进行调整,推荐第五种方案,因为新增字段对已有业务的影响最小。如果新增业务的话,方案三和方案五比较推荐。