今天去面试碰到的一个场景题,当时完全没有回答好,于是网上查资料看了下。
1. 前言
不知道大家有没有遇到这么一种业务场景,在业务中有个唯一约束 A,当该业务进行逻辑删除后(设置标记为删除状态),再往唯一约束列插入相同的值时,此时会报 Duplicate entry
,但在业务上,该值是必须要插入的。今天我们就来聊聊处理这种业务场景的几种思路。
2. 解决思路
- 方案一:不采用逻辑删除,直接物理删除
- 方案二:新建历史表。主表进行物理删除,同时将删除的记录保存到历史表中
- 方案三:取消表的唯一约束,同时引入
redis
来保证唯一约束。即取消表的唯一约束,在项目中引入 redis,通过redis 来判重,新增时往 redis set 记录,删除时,删除 redis 记录
- 方案四:变更删除标记为时间戳。将删除状态不以
0
,1
表示,而是以时间戳为值,然后将删除状态为与之前的唯一约束 A 重新组成唯一联合约束index(A、del_flag)
,删除时变更 del_flag 的时间戳
- 方案五:保留删除标记,同时新建一个字段
del_unique_key
。保留删除状态位,再新增一个字段del_unique_key
,该字段默认值为0
,字段类型的大小与主键 id 保持一致,同时与原先的唯一约束重新组成联合唯一约束 index(A,del_unique_key),业务进行逻辑删除,变更 del_unique_key 的值为该删除行的主键 id
3. 方案的取舍
方案一得从业务的角度上考虑了,如果物理删除,对业务无损,那就无所谓了。
方案二等于需要删除的记录的表都需要有历史表,如果仅仅是用来实现记录删除记录,感觉有点大材小用。
方案三引入 redis,虽然也可以解决问题,但是又额外增加复杂度,同时还得保证 redis 和数据库的一致性。
方案四和方案五其实实现的思路是一样,不过如果已经是在线上跑的业务,还是推荐用第五种方案,毕竟新增字段对已有的业务影响相对较小,如果是第四种方案,直接将标志位修改为时间戳,可能还会涉及改业务。如果是新增业务,第四种和第五种方案比较推荐。
2 条评论
联合唯一约束,可以试试创建/更新时间+逻辑删除+实际字段
确实。我现在采用的是上述的方案五,相比你这种方案还要多花一个字段来存储👍