golang,go,博客,开源,编程

认识gorm假删除

Published on with 0 views and 0 comments

在使用 GORM 时,假删除(Soft Delete)是一种常见的需求,目的是在删除数据时,并不从数据库中物理删除记录,而是通过标记某个字段为“已删除”状态来实现。这样可以保留数据的历史记录,同时避免在查询时看到这些已删除的数据。

1. 假删除的实现

GORM 中,假删除通常是通过在数据库表中添加一个 deleted_at 字段来实现的。GORM 内置了对假删除的支持,通过 gorm.Model 或自定义的结构体字段来实现。

1.1 使用 gorm.Model 实现假删除

gorm.Model 是 GORM 提供的一个内置结构体,它包含了 IDCreatedAtUpdatedAtDeletedAt 字段。如果你的结构体嵌套了 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) 可以查询到已被假删除的数据。

2. 自定义字段实现假删除

如果不想使用 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 字段会被设置为当前时间,表示数据已被删除。

3. 常用的 GORM 假删除操作

  • 删除一条记录:db.Delete(&user) 会将记录的 DeletedAt 字段设置为当前时间,表示该记录被删除,但实际数据没有从数据库中物理删除。
  • 查询未删除记录: 默认情况下,GORM 会自动过滤掉已删除的记录。如果你查询时不想包括已删除的记录,可以直接使用 db.First(), db.Where() 等。
  • 查询所有记录(包括已删除): 如果你需要查询所有记录,包括假删除的记录,可以使用 Unscoped() 方法:
    var user User
    db.Unscoped().First(&user) // 包括已删除的数据
    
  • 恢复已删除记录(恢复假删除): 如果你想恢复假删除的数据,可以通过 UpdateColumnUpdateDeletedAt 字段清空:
    db.Model(&user).Update("deleted_at", nil) // 恢复数据
    

4. 实际应用

假删除常用于以下场景:

  1. 软删除用户数据: 用户删除账户时,可以通过假删除保留用户的所有数据,但不再展示或提供服务。
  2. 历史记录保留: 一些需要保留历史数据的应用,可能需要对删除记录进行标记,而不是彻底删除。
  3. 审计记录: 假删除操作可以帮助审计和追踪数据变动,避免意外的彻底删除。

5. 总结

GORM 的假删除功能非常实用,它通过将数据的 DeletedAt 字段设为非空值来标记数据已删除,而不从数据库中物理删除数据。这为数据保留和历史记录提供了极大的便利,同时避免了直接删除数据可能带来的问题。通过 Unscoped() 方法,你还可以轻松查询已删除的数据。


标题:认识gorm假删除
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/07/1736216069089.html
联系:scotttu@163.com