Skip to content

第38章:插件系统与高级扩展 ​

本章目标 ​

学完本章后,你将能够:

  1. 理解 GORM 的插件架构
  2. 配置 DBResolver 实现读写分离
  3. 了解分库分表插件(Sharding)
  4. 开发自定义 Plugin
  5. 了解 Callback 系统

前置知识 ​

  • 需要先学习:第04章(配置)、第25-28章(关联+钩子)

38.1 GORM 插件架构 ​

GORM 通过插件接口实现可扩展性:

go
type Plugin interface {
	Name() string
	Initialize(*gorm.DB) error
}

// 注册插件
db.Use(plugin)

内置/社区插件 ​

插件功能
DBResolver读写分离、多数据源
Sharding分库分表
OptimisticLock乐观锁
Prometheus监控指标
Hints索引提示

38.2 DBResolver:读写分离 ​

go
import "gorm.io/plugin/dbresolver"

db, _ := gorm.Open(mysql.Open(masterDSN), &gorm.Config{})

db.Use(dbresolver.Register(dbresolver.Config{
	Sources:  []gorm.Dialector{mysql.Open("master_dsn")},  // 主库(写入)
	Replicas: []gorm.Dialector{
		mysql.Open("slave1_dsn"),  // 从库1(读取)
		mysql.Open("slave2_dsn"),  // 从库2(读取)
	},
	Policy: dbresolver.RandomPolicy{},  // 随机选择从库
}))

// 写操作 → 自动使用主库
db.Create(&user)

// 读操作 → 自动使用从库
db.Find(&users)

// 强制使用主库读
db.Clauses(dbresolver.Write).Find(&users)

38.3 自定义 Plugin ​

go
// 自动填充创建人和更新人的插件
type AuditPlugin struct{}

func (p *AuditPlugin) Name() string {
	return "audit_plugin"
}

func (p *AuditPlugin) Initialize(db *gorm.DB) error {
	// 注册 BeforeCreate 回调
	db.Callback().Create().Before("gorm:create").Register("audit:before_create", func(db *gorm.DB) {
		if db.Statement.Schema != nil {
			if field, ok := db.Statement.Schema.FieldsByName["CreatedBy"]; ok {
				field.Set(db.Statement.Context, db.Statement.ReflectValue, "system")
			}
		}
	})
	return nil
}

// 使用
db.Use(&AuditPlugin{})
// 之后所有 Create 操作自动填充 CreatedBy

38.4 Callback 系统简介 ​

GORM 内部所有操作都是通过 Callback 实现的。你可以注册自己的 Callback 来拦截和修改 SQL 执行流程:

go
// 注册一个 Callback
db.Callback().Create().Before("gorm:create").Register("my_callback", func(db *gorm.DB) {
	// 在 Create 之前执行
	log.Println("即将执行 INSERT")
})

// Callback 类型
db.Callback().Create()   // 创建
db.Callback().Update()   // 更新
db.Callback().Delete()   // 删除
db.Callback().Query()    // 查询
db.Callback().Row()      // Row
db.Callback().Raw()      // Raw

38.5 常用社区插件 ​

bash
# DBResolver(读写分离)
go get gorm.io/plugin/dbresolver

# OptimisticLock(乐观锁)
go get gorm.io/plugin/optimisticlock

# Prometheus(监控)
go get gorm.io/plugin/prometheus

# Sharding(分表)
go get gorm.io/sharding

本章小结 ​

  • GORM 通过 Plugin 接口实现扩展性
  • DBResolver 实现读写分离(主库写、从库读)
  • 自定义 Plugin 可以拦截操作流程
  • Callback 是 GORM 内部的操作钩子

练习题 ​

  1. 配置 DBResolver 实现读写分离(至少需要两个 MySQL 实例,可用 Docker)。
  2. 写一个自定义 Plugin,在每次 Create 前打印日志。
  3. 注册一个 AfterFind Callback,在查询结果返回前做数据脱敏。
  4. (思考题)读写分离的延迟问题怎么处理?即主库写入后,从库还没同步,用户立即读到旧数据?

把零散知识,整理成可以反复走的路。