场景描述
gorm框架中有一个Model结构体,大多数入库的结构体都会组合它
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt DeletedAt `gorm:"index"`
}
gorm采取的是软删除策略,即用一个DeleteAt字段来表示是否被删除,而不去实际删除对应的记录
这样可以防止数据丢失,方便后面维护找回数据
然而这样有一个问题
假如结构体有个字段是unique唯一的,就会出现一个逻辑上的错误:明明没有同名字段的记录,却还是因为唯一性无法插入新纪录
比方说用户名是唯一的,有个名为KreanXie的老用户注销了,数据库了软删除了他的信息,此时有个新用户想叫KreanXie,却因为因为用户名唯一而注册失败
场景还原
假设有这样一个结构体
type User struct {
gorm.Model
Username string `gorm:"unique"`
}
他的Username字段是unique的
此时我们插入一个新的字段
然后删除它
此时如果我们再次创建一个Username相同的记录,就会报错
Error 1062 (23000): Duplicate entry 'KreanXie' for key 'users.uni_users_username'
因为Username是唯一的,所以不允许拥有相同字段的记录插入
那么应该怎么在使用软删除的同时保证字段唯一性呢?
解决方案
Gorm官方提供了一个方案,使用时间戳表示DeletedAt,同时利用组合索引保证唯一性,具体做法如下
获取需要的包
go get -u gorm.io/plugin/soft_delete
重新设计User结构体,将DeletedAt的类型改为soft_delete.DeletedAt
同时还需要把DeletedAt另一个唯一的字段,假设是Username,加上一个taggorm:"uniqueIndex:unique_idx
,表示唯一索引
修改后
type User struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:unique_idx"`
Username string `gorm:"uniqueIndex:unique_idx"`
}
同样的,我们创建一个记录然后删除它
再次创建一个同样Username的记录,成功!
再次插入一条同名记录,发现会被唯一性约束
Error 1062 (23000): Duplicate entry '0-KreanXie' for key 'users.unique_idx'
如此,我们就实现了我们的目的,在使用软删除的同时保证字段唯一性
结语
这个场景应该还是很常见的,故记之
Author:KreanXie