0


软删除和唯一索引,二者不可得兼?

原创不易,未经允许,请勿转载。

文章目录

什么是软删除?

在说软删除之前,我们先来说一下什么是硬删除?硬删除也就是物理删除,是直接把数据从数据库中移除出去的,比如当用户执行了某个删除操作时,数据库就会相应的执行

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;

如果这篇文章对您有所帮助,麻烦点个一键三连。

原创不易,未经允许,请勿转载。

博客主页:https://xiaojujiang.blog.csdn.net/

标签: golang

本文转载自: https://blog.csdn.net/qq_43058685/article/details/123276097
版权归原作者 jiangxiaoju 所有, 如有侵权,请联系我们删除。

“软删除和唯一索引,二者不可得兼?”的评论:

还没有评论