database

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DriverMySQL    = config.DriverMySQL
	DriverPostgres = config.DriverPostgres
)

内置驱动常量(更多驱动可通过 RegisterDialect 扩展)

Variables

View Source
var DefaultManager atomic.Pointer[Manager]

DefaultManager 默认数据库管理器,包级 facade 代理到它。

主线A 修复:改用 atomic.Pointer 保护读写,消除原裸指针(外部直接 `database.DefaultManager = ...` 赋值与请求 goroutine 经 facade 读取)之间的数据竞争。 与 config.defaultManager / database.DefaultRedis / storage.DefaultStorage / cache.defaultCachePtr / jwt.defaultManager 对齐——框架内包级可变全局一律 atomic.Pointer。

类型由 *Manager 变更为 atomic.Pointer[Manager](breaking):下游若直接调用 DefaultManager.Init/Master 等方法需改用 InitDB/GetDB 等 facade,或 DefaultManager.Load().Init(...),或经 GetDefaultManager() 取实例后再调方法。

DefaultRedis 默认 Redis 管理器,包级 facade 代理到它。

C-1/H-4 修复:改用 atomic.Pointer 保护读写,消除原裸指针置换(SetDefaultRedisManager) 与请求 goroutine 无锁读(GetRedis 等 facade)之间的数据竞争。与 config.defaultManager 对齐。类型由 *RedisManager 变更为 atomic.Pointer[RedisManager](breaking:下游若直接 调用 DefaultRedis.Init 等方法需改用 InitRedis 等 facade,或 DefaultRedis.Load().Init)。

Functions

func AutoMigrate

func AutoMigrate() error

AutoMigrate 自动迁移数据库表结构(由应用通过 WithMigrator/WithModels 注册)

func Close

func Close() error

Close 关闭所有数据库连接(主库与从库),等价于 CloseAll。 历史上仅关闭主库、遗留从库池泄漏(C11f),已修正为委托 CloseAll。

func CloseAll

func CloseAll() error

CloseAll 关闭所有数据库连接(包括从库)

func CloseRedis

func CloseRedis() error

CloseRedis 关闭 Redis 连接

func Dialector

func Dialector(cfg *config.Config) gorm.Dialector

Dialector 根据配置返回 GORM Dialector。 驱动由 cfg.Database.Driver 决定;未指定时默认 MySQL,非空但未注册时返回会初始化失败的 Dialector,避免拼写错误静默回退到 MySQL。

func GetDB

func GetDB() *gorm.DB

GetDB 获取数据库实例(默认主库,兼容旧代码)

func GetDBFromContext

func GetDBFromContext(ctx context.Context) *gorm.DB

GetDBFromContext 根据上下文选择数据库

func GetReadDB

func GetReadDB() *gorm.DB

GetReadDB 获取读库实例(按策略选择从库)

func GetRedis

func GetRedis() *redis.Client

GetRedis 获取 Redis 客户端(未初始化返回 nil)。

H-4 修复:单源——仅从 DefaultRedis.Load().Client() 取,废弃原包级 redisClient 回退路径(其在 manager 替换后会返回 stale client,且无锁读存在竞态)。 测试注入的 mock client 经 SetTestRedisClient 直接设在当前 manager 上,闭环一致。

func GetReplicas

func GetReplicas() []*gorm.DB

GetReplicas 获取所有从库实例

func GetWriteDB

func GetWriteDB() *gorm.DB

GetWriteDB 获取写库实例(主库)

func HealthCheck

func HealthCheck() map[string]bool

HealthCheck 健康检查(主库 + 从库),单次 ping 限 3s 超时(M11)。

func HealthCheckRedis

func HealthCheckRedis(ctx context.Context) error

HealthCheckRedis Redis 健康检查

func InitDB

func InitDB(ctx context.Context, cfg *config.Config) error

InitDB 初始化数据库连接(带重试机制),驱动由配置决定。

func InitDBWithReplicas

func InitDBWithReplicas(ctx context.Context, cfg *config.Config, replicaDSNs []string) error

InitDBWithReplicas 初始化数据库主从连接,驱动由配置决定

func InitRedis

func InitRedis(cfg *config.Config) error

InitRedis 初始化 Redis 连接

func IsDBHealthy added in v1.1.0

func IsDBHealthy() bool

IsDBHealthy 返回主库探活健康状态(#21)。 与 HealthCheck()(实时 ping)不同,这是后台探活维护的缓存标记, 供 readiness 探针快速判断是否接流量,避免每次探针都同步 ping。

func ReadQuery

func ReadQuery(ctx context.Context, model any, query string, args ...any) error

ReadQuery 读查询。遵循 ctx 中的数据库路由标记;未指定时默认走从库。

func RegisterDialect

func RegisterDialect(spec DialectSpec)

RegisterDialect 注册一种数据库方言。 同时把 DSN 构建器登记到 config 包,使 cfg.Database.DSN() 也能识别新驱动。 已注册的同名驱动会被覆盖。

用法示例(接入 SQLite):

import "gorm.io/driver/sqlite"

database.RegisterDialect(database.DialectSpec{
    Name:      "sqlite",
    Dialector: func(dsn string) gorm.Dialector { return sqlite.Open(dsn) },
    DSN:       func(c *config.DatabaseConfig) string { return c.Name }, // 文件路径
})

func RegisteredDialects

func RegisteredDialects() []string

RegisteredDialects 返回所有已注册的驱动名(用于诊断)

func SetDefaultManager added in v1.2.0

func SetDefaultManager(m *Manager)

SetDefaultManager 提升指定 Manager 为全局默认,并关闭被替换的旧 Manager。 用于多实例场景或测试注入。nil 被忽略以防 facade Load 到 nil panic。 若调用方需要保留旧 Manager 用于回滚,请使用 SwapDefaultManager。

func SetDefaultRedisManager added in v1.1.0

func SetDefaultRedisManager(m *RedisManager)

SetDefaultRedisManager 提升指定 RedisManager 为全局默认,并关闭被替换的旧 Manager。 用于多实例场景或测试注入 mock。并发安全。若调用方需要保留旧 Manager 用于回滚,请使用 SwapDefaultRedisManager。

func SetReplicaPicker

func SetReplicaPicker(p ReplicaPicker)

SetReplicaPicker 设置默认管理器的从库选择策略

func SetTestRedisClient added in v1.2.0

func SetTestRedisClient(c *redis.Client) *redis.Client

SetTestRedisClient 供测试注入 miniredis 等 mock 客户端。 返回旧客户端引用以便测试清理时恢复。生产代码严禁调用。

H-4 修复:改为在当前默认 manager 上持锁替换 client(setClientForTest), 不再写独立的包级 redisClient 变量,消除双源真相与无锁写竞态。

约束:操作 DefaultRedis.Load() 返回的当前默认 manager。测试应避免在调用本函数 的同时并发 SetDefaultRedisManager 替换默认 manager,否则注入/恢复会作用到不同 manager 上。典型用法为 init 阶段注入、t.Cleanup 恢复,串行执行。

func StartDBProbing added in v1.1.0

func StartDBProbing(ctx context.Context)

StartDBProbing 启动主库/从库探活后台循环(#21)。 阻塞,应通过 App.Go 在独立 goroutine 运行;ctx 取消时退出。

func Transaction

func Transaction(fn func(tx *gorm.DB) error) error

Transaction 事务操作(自动使用主库)

func TransactionWithContext

func TransactionWithContext(ctx context.Context, fn func(tx *gorm.DB) error) error

TransactionWithContext 带上下文的事务操作

func TxFromContext added in v1.2.0

func TxFromContext(ctx context.Context) *gorm.DB

TxFromContext 取出 ctx 携带的外层事务;无则返回 nil。

func UseMaster

func UseMaster(ctx context.Context) context.Context

UseMaster 强制使用主库(用于事务或需要实时数据的场景)

func UseReplica

func UseReplica(ctx context.Context) context.Context

UseReplica 强制使用从库(用于报表查询等场景)

func WithTx added in v1.2.0

func WithTx(ctx context.Context, tx *gorm.DB) context.Context

WithTx 将外层事务注入 ctx,使上层(如 repository.BaseRepo)在调用时能 join 到该事务 而非另开连接/路由到主从库(H6c)。

用法:

err := database.TransactionWithContext(ctx, func(tx *gorm.DB) error {
    ctx2 := database.WithTx(ctx, tx)
    // 传 ctx2 给 repo 方法,repo 内部会优先使用该 tx
    return repo.FindByID(ctx2, id) // 此查询参与外层事务
})

注意:tx 仅在该 ctx 的生命周期内有效;事务提交/回滚后不得再用该 ctx 携带的 tx。

func WriteQuery

func WriteQuery(ctx context.Context, model any, query string, args ...any) error

WriteQuery 在主库上执行查询并扫描到 model(强制主库,绕过从库延迟)。 注意:命名沿用历史,实际用 .Find() 扫描结果集(读取语义),并非写操作—— 强制主库是为了读到刚写入的最新数据(read-your-writes)。命名误导见 M11。

Types

type DialectSpec

type DialectSpec struct {
	// Name 驱动主名称(如 "mysql"、"postgres"、"sqlite"),大小写不敏感
	Name string
	// Aliases 驱动别名(如 postgres 的 "postgresql"、"pg")
	Aliases []string
	// Dialector 由 DSN 构造 GORM Dialector
	Dialector DialectorFactory
	// DSN 由 DatabaseConfig 拼接连接字符串。可选。
	// 不提供时仅 CustomDSN 能直接生效;需要由配置字段拼接连接串的自定义驱动应显式提供该函数。
	DSN config.DSNBuilder
}

DialectSpec 描述一种数据库方言:如何建立连接 + 如何拼接 DSN

type DialectorFactory

type DialectorFactory func(dsn string) gorm.Dialector

DialectorFactory 根据 DSN 返回 GORM Dialector

func LookupDialect

func LookupDialect(driver string) (DialectorFactory, bool)

LookupDialect 查找已注册的 Dialector 工厂

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager 数据库管理器,持有主库与从库连接实例

func GetDefaultManager added in v1.2.0

func GetDefaultManager() *Manager

GetDefaultManager 返回全局默认 Manager(atomic 读取,并发安全)。 替代直接读 DefaultManager 包级变量(类型已改为 atomic.Pointer,直接读得到的是 atomic 值而非 *Manager)。需直接持有 Manager 调用其方法时用本函数或 DefaultManager.Load()。

func NewManager

func NewManager(cfg *config.Config) *Manager

NewManager 创建数据库管理器

func SwapDefaultManager added in v1.3.0

func SwapDefaultManager(m *Manager) *Manager

SwapDefaultManager 将指定 Manager 置为全局默认,并返回被替换的旧 Manager。 旧 Manager 不会被关闭,供 App 初始化这类需要失败回滚的生命周期流程暂存。 nil 被忽略,以防 facade Load 到 nil panic。

func (*Manager) Close

func (m *Manager) Close() error

Close 关闭主库与全部从库连接,并重置从库健康状态。 字段置空在锁内完成(保证新读取得到 nil),实际关闭在锁外执行避免持锁阻塞。

func (*Manager) FromContext

func (m *Manager) FromContext(ctx context.Context) *gorm.DB

FromContext 根据上下文选择数据库

func (*Manager) HealthCheck

func (m *Manager) HealthCheck(ctx context.Context) error

HealthCheck 健康检查,主库不可达时返回错误。

M11 完整覆盖(H-db-1 修复):ping 经 pingWithTimeout 受 healthCheckTimeout(3s) 约束, 使后台探活(probeOnce)与 /health 端点(app.go 经本方法)都不会被挂起 DB(连接活但不 响应)无限阻塞。ctx 自带更短 deadline 时优先尊重 ctx。

func (*Manager) InitDB

func (m *Manager) InitDB(ctx context.Context, cfg *config.Config) error

InitDB 初始化数据库连接(带重试机制),驱动由配置决定。 ctx 控制 Ping 与重试等待;调用方取消 ctx 时初始化会尽快返回。

func (*Manager) InitDBWithReplicas

func (m *Manager) InitDBWithReplicas(ctx context.Context, cfg *config.Config, replicaDSNs []string) error

InitDBWithReplicas 初始化数据库主从连接,驱动由配置决定 replicaDSNs: 从库连接字符串列表(需与主库驱动匹配)

func (*Manager) IsHealthy added in v1.1.0

func (m *Manager) IsHealthy() bool

IsHealthy 返回主库当前健康状态(#21)。供 readiness/health 探针联动。

func (*Manager) Master

func (m *Manager) Master() *gorm.DB

Master 返回主库实例。 经 m.mu 锁保护读取,避免与 InitDB/Close 的写竞争返回已关闭/nil 池(C11d)。

func (*Manager) Open

func (m *Manager) Open(ctx context.Context) error

Open 打开主库连接

func (*Manager) OpenWithReplicas

func (m *Manager) OpenWithReplicas(ctx context.Context, replicaDSNs []string) error

OpenWithReplicas 打开主库与从库连接

func (*Manager) Picker

func (m *Manager) Picker() ReplicaPicker

Picker 返回当前从库选择策略

func (*Manager) Replica

func (m *Manager) Replica() *gorm.DB

Replica 按策略选择一个从库;无从库时返回主库。 #21:启用探活后,自动过滤不健康的从库;全不健康时回退到全部从库(仍可服务)。 全程持 m.mu 锁,避免 replicas/master 与重建路径写竞争(C11d)。

func (*Manager) Replicas

func (m *Manager) Replicas() []*gorm.DB

Replicas 返回所有从库实例的拷贝。 经 m.mu 锁保护读取并返回拷贝,避免调用方持活切片与 InitDBWithReplicas/Close 重置竞争(C11d)。

func (*Manager) SetPicker

func (m *Manager) SetPicker(p ReplicaPicker)

SetPicker 设置从库选择策略

func (*Manager) StartProbing added in v1.1.0

func (m *Manager) StartProbing(ctx context.Context)

StartProbing 启动主库与从库的健康探活后台循环(#21)。 阻塞调用方,应通过 App.Go 在独立 goroutine 运行;ctx 取消时退出。 周期 ping 主库,连续失败达阈值后标记不健康(IsHealthy=false); 同时 ping 各从库,失败则从读流量剔除,恢复后自动重新纳入。

type RandomPicker

type RandomPicker struct{}

RandomPicker 随机选择从库。

使用 crypto/rand 生成随机索引,并发安全且不可预测。len(replicas)<=0 返回 nil; crypto/rand 失败(极罕见,如熵池耗尽)时回退到 replicas[0],保证可用性。

func (*RandomPicker) Pick

func (p *RandomPicker) Pick(replicas []*gorm.DB) *gorm.DB

Pick 随机选择一个从库

type RedisManager added in v1.1.0

type RedisManager struct {
	// contains filtered or unexported fields
}

RedisManager Redis 连接管理器(#10)。照 database.Manager 模式: 实例化 + DefaultRedis 全局默认 + 包级 facade 代理,支持多实例与测试注入。

func GetDefaultRedisManager added in v1.3.0

func GetDefaultRedisManager() *RedisManager

GetDefaultRedisManager 返回当前默认 Redis 管理器。

func NewRedisManager added in v1.1.0

func NewRedisManager() *RedisManager

NewRedisManager 创建 Redis 管理器实例。

func SwapDefaultRedisManager added in v1.3.0

func SwapDefaultRedisManager(m *RedisManager) *RedisManager

SwapDefaultRedisManager 将指定 RedisManager 置为全局默认,并返回被替换的旧 Manager。 旧 Manager 不会被关闭,供 App 初始化这类需要失败回滚的生命周期流程暂存。 nil 被忽略,以防 facade Load 到 nil panic。

func (*RedisManager) Client added in v1.1.0

func (m *RedisManager) Client() *redis.Client

Client 返回当前 Redis 客户端(未初始化返回 nil)。

func (*RedisManager) Close added in v1.1.0

func (m *RedisManager) Close() error

Close 关闭 Redis 连接。

func (*RedisManager) HealthCheck added in v1.1.0

func (m *RedisManager) HealthCheck(ctx context.Context) error

HealthCheck Redis 健康检查。

func (*RedisManager) Init added in v1.1.0

func (m *RedisManager) Init(cfg *config.Config) error

Init 初始化 Redis 连接并 ping 验证。

type ReplicaPicker

type ReplicaPicker interface {
	Pick(replicas []*gorm.DB) *gorm.DB
}

ReplicaPicker 从库选择策略

type RoundRobinPicker

type RoundRobinPicker struct {
	// contains filtered or unexported fields
}

RoundRobinPicker 轮询选择从库

func (*RoundRobinPicker) Pick

func (p *RoundRobinPicker) Pick(replicas []*gorm.DB) *gorm.DB

Pick 轮询选择一个从库

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL