高级主题

DBResolver

qianmoQqianmoQ· 更新于 2026-09-23· 阅读 7 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

DBResolver 为 GORM 添加了多数据库支持,支持以下功能:

  • 多个主库与从库
  • 读写分离
  • 根据当前操作的表/结构体自动切换连接
  • 手动切换连接
  • 主库/从库负载均衡
  • 支持 RAW SQL
  • 支持事务

https://github.com/go-gorm/dbresolver

使用方式

import (
  "gorm.io/gorm"
  "gorm.io/plugin/dbresolver"
  "gorm.io/driver/mysql"
)

db, err := gorm.Open(mysql.Open("db1_dsn"), &gorm.Config{})

db.Use(dbresolver.Register(dbresolver.Config{
  
  Sources:  []gorm.Dialector{mysql.Open("db2_dsn")},
  Replicas: []gorm.Dialector{mysql.Open("db3_dsn"), mysql.Open("db4_dsn")},
  
  Policy: dbresolver.RandomPolicy{},
  
  TraceResolverMode: true,
}).Register(dbresolver.Config{
  
  Replicas: []gorm.Dialector{mysql.Open("db5_dsn")},
}, &User{}, &Address{}).Register(dbresolver.Config{
  
  Sources:  []gorm.Dialector{mysql.Open("db6_dsn"), mysql.Open("db7_dsn")},
  Replicas: []gorm.Dialector{mysql.Open("db8_dsn")},
}, "orders", &Product{}, "secondary"))

自动切换连接

DBResolver 会根据当前操作的表/结构体自动切换连接。

对于 RAW SQL,DBResolver 会从 SQL 中提取表名来匹配 resolver,并且除非 SQL 以 SELECT 开头(SELECT... FOR UPDATE 除外),否则会使用 sources,例如:


db.Table("users").Rows() 
db.Model(&User{}).Find(&AdvancedUser{}) 
db.Exec("update users set name = ?", "jinzhu") 
db.Raw("select name from users").Row().Scan(&name) 
db.Create(&user) 
db.Delete(&User{}, "name = ?", "jinzhu") 
db.Table("users").Update("name", "jinzhu") 


db.Find(&Pet{}) 
db.Save(&Pet{}) 


db.Find(&Order{}) 
db.Table("orders").Find(&Report{}) 

读写分离

DBResolver 基于当前使用的 GORM 回调 实现读写分离。

对于 Query、Row 回调,除非指定了 Write 模式,否则将使用 replicas
对于 Raw 回调,语句被视为只读,如果 SQL 以 SELECT 开头则将使用 replicas

手动切换连接


db.Clauses(dbresolver.Write).First(&user)


db.Clauses(dbresolver.Use("secondary")).First(&user)


db.Clauses(dbresolver.Use("secondary"), dbresolver.Write).First(&user)

事务

使用事务时,DBResolver 将持续使用当前事务,不会根据配置切换到主库/从库

但你可以在开始事务之前指定使用哪个数据库,例如:


tx := db.Clauses(dbresolver.Read).Begin()


tx := db.Clauses(dbresolver.Write).Begin()


tx := db.Clauses(dbresolver.Use("secondary"), dbresolver.Write).Begin()

负载均衡

GORM 支持基于策略对主库/从库进行负载均衡,策略应为实现以下接口的结构体:

type Policy interface {
  Resolve([]gorm.ConnPool) gorm.ConnPool
}

目前仅实现了 RandomPolicy,如果未指定其他策略,它将是默认选项。

连接池

db.Use(
  dbresolver.Register(dbresolver.Config{  }).
  SetConnMaxIdleTime(time.Hour).
  SetConnMaxLifetime(24 * time.Hour).
  SetMaxIdleConns(100).
  SetMaxOpenConns(200)
)

GitHub tag (latest SemVer)

评论

登录后参与评论

正在加载评论…