原创不易,未经允许,请勿转载。
文章目录
什么是软删除?
在说软删除之前,我们先来说一下什么是硬删除?硬删除也就是物理删除,是直接把数据从数据库中移除出去的,比如当用户执行了某个删除操作时,数据库就会相应的执行
delete xxx where xxx
这种操作。使用这种删除方式的话,数据是不可恢复的,如果一定要恢复的话,只能通过日志。
而软删除也叫做逻辑删除,它并不是真正的把数据删除,而是用一个字段来标记当前数据是否是被删除的。使用软删除的时候,通常会在表中增加一个字段
deletedAt
表示是否删除,如果
deletedAt
字段类型为boolean的话,0可以表示未删除,1表示删除。若是
deletedAt
为
datetime
类型的话,如果数据未被删除,则该字段为null,否则则为删除的时间。
当使用软删除时,假设
deletedAt
字段为
datetime
类型,那么当执行删除操作时,会把原本的
delete xxx
变成
update set deleteAt=now() where xxx
。而在实行查询或者更新操作时,都会在条件中加上
deletedAt is not null
,例如
select * from xxx where deletedAt is not null
怎么实现软删除?
正如上面所说,实现软删除一般都是通过一个字段来做标记。一般的orm框架都集成了软删除的功能。
例如Java中的Mybatis-Plus,就提供了软删除的实现,(下面这段说明摘抄自Mybatis-Plus官方文档)
说明:
只对自动注入的 sql 起效:
- 插入: 不作限制
- 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 删除: 转变为 更新
例如:
- 删除: update user set deleted=1 where id = 1 and deleted=0
- 查找: select id,name,deleted from user where deleted=0
字段类型支持说明:
- 支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
- 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()
在Go语言中,GORM框架也提供了软删除的支持。(以下摘抄自gorm官方文档)
如果您的模型包含了一个 gorm.deletedat 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!
拥有软删除能力的模型调用 Delete 时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt 置为当前时间, 并且你不能再通过正常的查询方法找到该记录。
// user 的 ID 是 `111`
db.Delete(&user)// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;// 批量删除
db.Where("age = ?",20).Delete(&User{})// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
如果您不想引入 gorm.Model,您也可以这样启用软删除特性:
type User struct{
ID int
Deleted gorm.DeletedAt
Name string}
什么是唯一索引?
唯一索引指的是在数据库层面来约束数据的唯一性。唯一索引可以建立在一个字段上,也可以是在多个字段上。例如账号是不可以重复的,那么就需要在账号这个字段上,加上唯一索引进行约束。比如对于同一个课程,每个学生只能选择一次,那么就需要在学生ID和课程ID这两个字段上建立唯一索引进行约束。
软删除和唯一索引只能选一个?
最近在做的项目中遇到了这么一个问题。
有一个用户表,定义如下,在username字段上用了唯一索引标注,使用deleted_at字段标记是否删除。
createtableuser(
id intnotnull,
username varchar(20)notnullunique,
deleted_at datetimedefaultnull,primarykey(id))
比如
username
为
xiaoming
的用户被删除了(即
delete_at
字段不为
null
了),之后有添加添加
username
为
xiaoming
的用户就会报错。因为虽然之前的
xiaoming
是被删除了,但是实际还是存在表中的,只是我们看不到了而已。
既然这样不行,那该怎么办?我们可以用联合唯一索引的形式,
unique key uk_username_deleted(username,deleted_at)
在
username
和
deleted_at
这两个字段上建立唯一索引约束。
不过这看似解决问题了,但是当我尝试的时候,又双叒叕出现了问题。
插入了两个username为xiaoming的数据也可以。这是因为
deleted_at
字段默认为
null
,导致索引失效了。
既然当
deleted_at
默认为null的时候会导致索引失效,那不如我们可以给
deleted_at
一个默认值,比如把
deleted_at
字段改成int类型,未删除则用0表示,删除的话,则填入删除时的时间戳。
因为项目中是使用gorm作为数据库操作的,而它默认提供的软删除方案则是上面说所的使用时间来标记是否删除了。不过好在官方gorm官方也提供了第二种方案,
这个插件实现了我所说的第二种解决思路。
import"gorm.io/plugin/soft_delete"type User struct{
ID uint
Name string
DeletedAt soft_delete.DeletedAt
}// Query
SELECT * FROM users WHERE deleted_at =0;// Delete
UPDATE users SET deleted_at =/* current unix second */ WHERE ID =1;
如果这篇文章对您有所帮助,麻烦点个一键三连。
原创不易,未经允许,请勿转载。
版权归原作者 jiangxiaoju 所有, 如有侵权,请联系我们删除。