MySQL 软删除与唯一性约束共存方案
一、背景
今天运营反馈了一个策略新建失败的问题。失败原因是新增策略名称与存量数据的策略名称重复,且策略名称为唯一索引,insert时触发数据库唯一键约束导致插入失败。但占用该名称的策略已经被删除了,业务上处于不可见状态。
这是由软删除设计与唯一性约束引发的冲突问题,怎么解呢?
二、示例环境
表名 : t_strategy
字段名 | 描述 | 类型 |
---|---|---|
id | 策略ID | VARCHAR(32) |
name | 策略名称 | VARCHAR(64) |
is_deleted | 删除状态(0:生效中;1:已删除;) | TINYINT(4) |
业务唯一键 : name
数据库唯一键 : name
三、方案选型
3.1 物理删除
物理删除没有这个烦恼,但得从业务和所在环境的角度上考虑是否可行。
所在的业务和团队是否允许物理删除?
对于存量重复记录如何订正?
跑题了~
3.2 is_deleted 存储删除时间
is_deleted 为 0 时,代表记录生效中;is_deleted 非 0 时,代表记录已删除,且字内容为删除时间。
数据库唯一键调整为 : name + is_deleted
示例环境的 is_deleted 类型为 TINYINT ,该方案涉及表结构变更。
如上,所在的业务和环境是否允许此操作?
3.3 is_deleted 存储业务唯一键下的自增值
is_deleted 为 0 时,代表记录生效中;is_deleted 非 0 时,代表记录已删除,且字内容为“自增值”。
数据库唯一键调整为 : name + is_deleted
TINYINT 的值范围有限,能否满足业务诉求?
“自增”逻辑需要自行实现,且依赖一次查询。
3.4 补充业务唯一键
3.4.1 新增 deleted_time 字段
deleted_time 即删除时间。
deleted_time 默认值为 NULL 或者 0 ;记录被删除时,将 deleted_time 赋值为 now()。
数据库唯一键调整为 : name + deleted_time
逻辑自洽,通俗易懂
实现上比较简单,在软删时将 deleted_time 置为 now() 即可。
3.4.2 新增 deleted_primary_key 字段
deleted_primary_key 即删除的主键。
deleted_primary_key 默认值为 NULL 或者 0 ;记录被删除时,将 deleted_primary_key 赋值为行主键。
数据库唯一键调整为 : name + deleted_primary_key
实现上也比较简单,在软删时将 deleted_primary_key 置为 id 即可。
3.5 删除数据分表存储
删除数据由删除表统一保存,原表不再保存删除数据,仅原表保持uk校验。
is_deleted 默认值为 0 ;记录被删除时,将该数据插入到删除表。
如果所在的业务和环境允许物理删除,那么压根不存在软删问题;如果不允许,记录删除时,将 is_deleted 赋值为 1。
当业务主键冲突时有两种情况,业务失败或者数据覆盖。
技术实现相比上述几个方案更为复杂,不建议使用。
常规方案推荐
3.2 is_deleted 存储删除时间
> 3.4.1 新增 deleted_time 字段
> 3.4.2 新增 deleted_primary_key 字段
is_deleted 不需要或者所在业务和环境允许表结构变更,优先选取方案 :
3.2 is_deleted 存储删除时间
,否则往下走。
如果 deleted_time 能满足未来并发诉求,则用方案3.4.1 新增 deleted_time 字段
;否者采用方案4.2 新增 deleted_primary_key 字段
。
从业务语义上看,删除时间本身是带业务含义的,只是当前业务没有用到。而被删除的主键,仅仅只是为了解决技术上的问题,没有带来增量的业务价值。
- 0
- 0
-
分享