golang,go,博客,开源,编程
在使用 GORM
时,假删除(Soft Delete)是一种常见的需求,目的是在删除数据时,并不从数据库中物理删除记录,而是通过标记某个字段为“已删除”状态来实现。这样可以保留数据的历史记录,同时避免在查询时看到这些已删除的数据。
在 GORM
中,假删除通常是通过在数据库表中添加一个 deleted_at
字段来实现的。GORM
内置了对假删除的支持,通过 gorm.Model
或自定义的结构体字段来实现。
gorm.Model
实现假删除gorm.Model
是 GORM 提供的一个内置结构体,它包含了 ID
、CreatedAt
、UpdatedAt
和 DeletedAt
字段。如果你的结构体嵌套了 gorm.Model
,则默认启用了假删除功能。
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
type User struct {
gorm.Model // 包含 ID, CreatedAt, UpdatedAt, DeletedAt 字段
Name string
Age int
}
func main() {
// 初始化 GORM,连接 SQLite 数据库
db, err := gorm.Open("sqlite3", "gorm.db")
if err != nil {
fmt.Println("Failed to connect to database:", err)
return
}
defer db.Close()
// 自动迁移
db.AutoMigrate(&User{})
// 创建新用户
user := User{Name: "John", Age: 30}
db.Create(&user)
// 执行假删除操作
db.Delete(&user)
// 查询删除的数据,GORM 会默认过滤掉已删除的数据
var u User
if err := db.First(&u, user.ID).Error; err != nil {
fmt.Println("Error fetching deleted user:", err)
} else {
fmt.Println("Found user:", u.Name)
}
// 如果想要查询包括已删除的数据,使用 Unscoped
var deletedUser User
if err := db.Unscoped().First(&deletedUser, user.ID).Error; err == nil {
fmt.Println("Found deleted user:", deletedUser.Name)
}
}
gorm.Model
包含了 ID
, CreatedAt
, UpdatedAt
, DeletedAt
字段,其中 DeletedAt
是用于标记假删除的字段。只要填充了 DeletedAt
字段,GORM 就会认为这条记录已被删除。db.Delete(&user)
会将记录的 DeletedAt
字段设置为当前时间,而不会删除数据库中的数据。db.First(&u, user.ID)
查询时,GORM 会自动忽略已删除的数据。db.Unscoped().First(&deletedUser, user.ID)
可以查询到已被假删除的数据。如果不想使用 gorm.Model
,你也可以自定义一个字段来实现假删除。例如,可以在模型中手动添加 DeletedAt
字段:
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
type User struct {
ID uint `gorm:"primary_key"`
Name string
Age int
DeletedAt *gorm.DeletedAt // 使用 *gorm.DeletedAt 类型表示假删除字段
}
func main() {
// 初始化 GORM,连接 SQLite 数据库
db, err := gorm.Open("sqlite3", "gorm.db")
if err != nil {
fmt.Println("Failed to connect to database:", err)
return
}
defer db.Close()
// 自动迁移
db.AutoMigrate(&User{})
// 创建新用户
user := User{Name: "John", Age: 30}
db.Create(&user)
// 执行假删除操作
db.Delete(&user)
// 查询删除的数据,GORM 会默认过滤掉已删除的数据
var u User
if err := db.First(&u, user.ID).Error; err != nil {
fmt.Println("Error fetching deleted user:", err)
} else {
fmt.Println("Found user:", u.Name)
}
// 如果想要查询包括已删除的数据,使用 Unscoped
var deletedUser User
if err := db.Unscoped().First(&deletedUser, user.ID).Error; err == nil {
fmt.Println("Found deleted user:", deletedUser.Name)
}
}
在上面的代码中,DeletedAt
字段是一个指向 gorm.DeletedAt
类型的指针。当数据被假删除时,DeletedAt
字段会被设置为当前时间,表示数据已被删除。
db.Delete(&user)
会将记录的 DeletedAt
字段设置为当前时间,表示该记录被删除,但实际数据没有从数据库中物理删除。GORM
会自动过滤掉已删除的记录。如果你查询时不想包括已删除的记录,可以直接使用 db.First()
, db.Where()
等。Unscoped()
方法:
var user User
db.Unscoped().First(&user) // 包括已删除的数据
UpdateColumn
或 Update
将 DeletedAt
字段清空:
db.Model(&user).Update("deleted_at", nil) // 恢复数据
假删除常用于以下场景:
GORM 的假删除功能非常实用,它通过将数据的 DeletedAt
字段设为非空值来标记数据已删除,而不从数据库中物理删除数据。这为数据保留和历史记录提供了极大的便利,同时避免了直接删除数据可能带来的问题。通过 Unscoped()
方法,你还可以轻松查询已删除的数据。