定义
软删除又叫逻辑删除,标记删除,删除后数据还具有意义的数据才需要做软删除功能
这种方式并不是真正的从数据库表中把记录删除,而是通过特定的标记方式标记此记录已被删除(在查询的时候过滤掉此记录),这样用户在界面上看起来就像是数据真的被删掉了,然而事实上却是库里还在。
软删除的实现通常有三种:
- 在表里添加布尔类型的字段,标记该记录是否被逻辑删除。
- 在表里添加删除时间(默认为null),如果有删除时间则表示此记录被逻辑删除,和第一种方式大差不差。
- 将逻辑删除的数据插入到另外一个表里。
软删除和硬删除的处理方法
实际上,并不是所有的记录都有必要被一直保留,过多的数据会导致查询效率低下,数据库臃肿。
比如许多程序的日志文件只会存留最近一周或者最近一月。对于更久的数据需要物理删除。
那么有没有既能实现软删除保留需要的数据又能在数据量过大的时候进行物理删除的办法呢,答案是有的。
可以为state字段赋予另一个意义,当它是2时(当然别的数值也行)不再保留,直接物理删除。
或者再声明一个字段isRecycle,来表示该记录需不需要直接删除。
这样在定期维护数据库的同时也可以删除不再需要的记录。
表中处理
- 硬删除(物理删除)
DELETE FROM t_product WHERE id = 123;
- 软删除(逻辑删除)
UPDATE t_product SET is_delete = 1 WHERE id = 123;
#在所有的业务查询的地方,都需要过滤掉已经删除的数据。
逻辑删除唯一索引解法
对于这种逻辑删除的表,是没法加唯一索引的。
其根本原因是,记录被删除之后,delete_status 会被设置成 1,默认是 0。相同的记录第二次删除的时候,delete_status 被设置成 1,但由于创建了唯一索引(把 name、model 和 delete_status 三个字段同时做成唯一索引),数据库中已存在 delete_status 为 1 的记录,所以这次会操作失败。
- 删除状态 +1
不要纠结于 delete_status 为 1,表示删除,当 delete_status 为 1、2、3 等等,只要大于 1 都表示删除。
这样的话,每次删除都获取那条相同记录的最大删除状态,然后加 1。
这样数据操作过程变成:
添加记录 a,delete_status=0。
删除记录 a,delete_status=1。
添加记录 a,delete_status=0。
删除记录 a,delete_status=2。
添加记录 a,delete_status=0。
删除记录 a,delete_status=3。
由于记录 a,每次删除时,delete_status 都不一样,所以可以保证唯一性。
该方案的优点是:
不用调整字段,非常简单和直接。
缺点是:
可能需要修改 sql 逻辑,特别是有些查询 sql 语句,有些使用 delete_status=1 判断删除状态的,需要改成 delete_status>=1。 - 增加时间戳字段
把 name、model、delete_status 和 timeStamp,四个字段同时做成唯一索引。
在添加数据时,timeStamp 字段写入默认值1。
然后一旦有逻辑删除操作,则自动往该字段写入时间戳。
这样即使是同一条记录,逻辑删除多次,每次生成的时间戳也不一样,也能保证数据的唯一性。
时间戳一般精确到秒。
除非在那种极限并发的场景下,对同一条记录,两次不同的逻辑删除操作,产生了相同的时间戳。
这时可以将时间戳精确到毫秒。
该方案的优点是:
可以在不改变已有代码逻辑的基础上,通过增加新字段实现了数据的唯一性。
缺点是:
在极限的情况下,可能还是会产生重复数据。 - 增加 id 字段
在添加数据时给 delete_id 设置默认值 1,然后在逻辑删除时,给 delete_id 赋值成当前记录的主键 id。
把 name、model、delete_status 和 delete_id,四个字段同时做成唯一索引。
这可能是最优方案,无需修改已有删除逻辑,也能保证数据的唯一性。