当前位置: 首页 > article >正文

【GORM】Hook钩子函数,Session会话函数讲解及使用案例

GORM 中的 Hook 与 Session 详解

1. Hook

1.1 什么是 Hook?

Hook 是 GORM 提供的回调机制,允许开发者在模型操作的生命周期(如创建、更新、删除)中嵌入自定义逻辑。通过 Hook,可以在数据库操作前后执行特定的代码。

1.2 支持的生命周期回调

GORM 提供以下回调函数方法名,可以定义在模型结构体中:

  • BeforeSave / AfterSave
  • BeforeCreate / AfterCreate
  • BeforeUpdate / AfterUpdate
  • BeforeDelete / AfterDelete
  • AfterFind

hook函数要定义成绑定结构体的方法,传入*gorm.DB,返回error

1.3 Hook 示例
package main

import (
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// User 模型,包含 Hook
type User struct {
	ID    uint
	Name  string
	Email string
}

// BeforeCreate 在创建之前执行逻辑
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
	fmt.Println("BeforeCreate: 验证用户数据")
	if u.Name == "" {
		return fmt.Errorf("用户名不能为空")
	}
	return nil
}

// AfterCreate 在创建之后执行逻辑
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
	fmt.Println("AfterCreate: 创建完成后,发送欢迎邮件")
	// 这里可以实现异步发送邮件的逻辑
	return nil
}

func main() {
	// 初始化数据库
	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	db.AutoMigrate(&User{})

	// 创建用户
	user := User{Name: "John Doe", Email: "john@example.com"}
	if err := db.Create(&user).Error; err != nil {
		fmt.Println("创建失败:", err)
	} else {
		fmt.Println("创建成功")
	}
}

  • hook函数会在对应行为开始前后自动调用
package _case

import (
	"fmt"
	"gorm.io/gorm"
)

// BeforeSave 事务开始前
func (t *Teacher) BeforeSave(tx *gorm.DB) error {
	fmt.Println("hook BeforeSave")
	return nil
}

func (t *Teacher) AfterSave(tx *gorm.DB) error {
	fmt.Println("hook AfterSave")
	return nil
}

func (t *Teacher) BeforeCreate(tx *gorm.DB) error {
	fmt.Println("hook BeforeCreate")
	return nil
}

func (t *Teacher) AfterCreate(tx *gorm.DB) error {
	fmt.Println("hook AfterCreate")
	return nil
}

func (t *Teacher) BeforeUpdate(tx *gorm.DB) error {
	fmt.Println("hook BeforeUpdate")
	return nil
}

func (t *Teacher) AfterUpdate(tx *gorm.DB) error {
	fmt.Println("hook AfterUpdatee")
	return nil
}

func (t *Teacher) BeforeDelete(tx *gorm.DB) error {
	fmt.Println("hook BeforeDelete")
	return nil
}

func (t *Teacher) AfterDelete(tx *gorm.DB) error {
	fmt.Println("hook AfterDelete")
	return nil
}

func (t *Teacher) AfterFind() error {
	fmt.Println("hook AfterFind")
	return nil
}


2. Session

2.1 什么是 Session?

Session 是 GORM 提供的一个上下文机制,用于管理数据库会话的状态,包括:

  • SQL 语句生成的选项。
  • 链式操作的隔离。
  • 自定义事务级别。
2.2 Session 功能

以下是常见的 Session 使用场景:

  1. 隔离链式调用:
    • 每次调用 Session,会创建一个独立的上下文,不会影响其他调用。
  2. 指定上下文:
    • 可以传入自定义的 context.Context
  3. 控制事务隔离级别:
    • 通过 Session 设置事务的隔离级别和是否启用事务。
  4. 禁用或启用功能:
    • 例如,跳过 Hook、忽略默认值、指定表名等。
2.3 Session 示例
package main

import (
	"context"
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func main() {
	// 初始化数据库
	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})

	// 1. 隔离链式调用
	fmt.Println("使用独立的 Session")
	sessionDB := db.Session(&gorm.Session{})
	sessionDB.Create(&User{Name: "Alice", Email: "alice@example.com"})

	// 2. 自定义 Context
	fmt.Println("传入自定义 Context")
	ctx := context.Background()
	db.WithContext(ctx).Create(&User{Name: "Bob", Email: "bob@example.com"})

	// 3. 跳过 Hook
	fmt.Println("跳过 Hook")
	db.Session(&gorm.Session{SkipHooks: true}).Create(&User{Name: "", Email: "hook@example.com"})

	// 4. 指定事务隔离级别
	fmt.Println("指定事务隔离级别")
	tx := db.Session(&gorm.Session{
		PrepareStmt: true,  // 启用缓存
		NewDB:       true,  // 开启新的 DB 实例
	}).Begin() // 开启事务
	defer tx.Rollback()

	tx.Create(&User{Name: "Charlie", Email: "charlie@example.com"})
	tx.Commit()
}

3. Hook 与 Session 的组合

在实际开发中,Hook 和 Session 常结合使用。例如,在订单系统中,可以通过 Hook 验证订单状态,同时通过 Session 确保操作隔离。

案例:订单创建流程
package main

import (
	"errors"
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type Order struct {
	ID         uint
	UserID     uint
	ProductID  uint
	Quantity   int
	Status     string
}

// BeforeSave 验证订单数据
func (o *Order) BeforeSave(tx *gorm.DB) (err error) {
	if o.Quantity <= 0 {
		return errors.New("订单数量必须大于0")
	}
	return nil
}

func main() {
	// 初始化数据库
	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	db.AutoMigrate(&Order{})

	// 使用 Session 创建订单
	sessionDB := db.Session(&gorm.Session{SkipHooks: false})
	order := Order{UserID: 1, ProductID: 2, Quantity: 5, Status: "Pending"}

	if err := sessionDB.Create(&order).Error; err != nil {
		fmt.Println("订单创建失败:", err)
	} else {
		fmt.Println("订单创建成功")
	}
}

总结

Hook 使用要点:
  1. 用于在模型操作前后插入自定义逻辑。
  2. 避免复杂逻辑嵌套在 Hook 中,保持简洁。
Session 使用要点:
  1. 隔离链式调用,避免上下文污染。
  2. 灵活控制事务、上下文和功能开关。
  3. 配合 Hook,可在定制操作的同时保留数据库上下文的灵活性。

https://github.com/0voice


http://www.kler.cn/a/513577.html

相关文章:

  • 2025年PHP面试宝典,技术总结。
  • CentOS部署FastDFS+Nginx并实现远程访问本地服务器中文件
  • STM32补充——FLASH
  • 如何使用MaskerLogger防止敏感数据发生泄露
  • 风吹字符起,诗意Linux:一场指令与自由的浪漫邂逅(上)
  • Mysql 主从复制原理及其工作过程,配置一主两从实验
  • 【2025小年源码免费送】
  • OFD实现在线预览的几种方式
  • 计算机的错误计算(二百一十八)
  • 【Golang/gRPC/Nacos】在golang中将gRPC和Nacos结合使用
  • 刷题日记3
  • 天机学堂7--Redisson自定义注解AOP以及SPEL表达式实现分布式锁
  • 顽固性失眠怎么调理
  • InVideo AI技术浅析(五):生成对抗网络
  • centos下设置服务器开机自启动 redis
  • MongoDB实训:电子商务日志存储任务
  • leetcode 面试经典 150 题:插入区间
  • 音频入门(一):音频基础知识与分类的基本流程
  • AIGC视频生成模型:Stability AI的SVD(Stable Video Diffusion)模型
  • python+pygame+pytmx+map editor开发一个tiled游戏demo 05使用object层初始化player位置
  • 前端 window.print() 打印图片
  • 云知声语音识别技术:原理、突破与应用前景
  • Python数据可视化(够用版):懂基础 + 专业的图表抛给Tableau等专业绘图工具
  • 常用邮箱有哪些推荐的服务?
  • tcpdump 精准分析vxlan网络
  • 前端缓存策略:强缓存与协商缓存深度剖析