GO分层架构【4】Repository获取 *gorm.DB

Repository(或 Infra) 要如何获取 *gorm.DB 对象的?是通过全局变量,还是通过结构体注入?

在 Go 的 GORM 开发中,获取 *gorm.DB 对象主要有两种流派:"简单粗暴型"和"工程严谨型"。

作为一名 Go 开发者,理解这两者的区别对你调整架构至关重要:

1. 全局变量模式(简单粗暴型)

这是很多教程里的写法。在 infra 包里定义一个全局变量 DB

  • 代码长这样:

    复制代码
    // internal/infra/db.go
    var DB *gorm.DB
    
    func InitDB() {
        db, _ := gorm.Open(...)
        DB = db
    }
  • 如何调用: 在任何地方(Handler/Logic/Repo)直接调用 infra.DB.Find(&user)

  • 评价:

    • 优点:写起来极快,不用传参。
    • 缺点:极其难测。如果你想写单元测试,或者想连接两个不同的数据库,全局变量会让你痛不欲生。而且这种隐藏的依赖关系会导致代码越写越乱。

2. 结构体注入模式(工程严谨型 - 推荐)

这是主流微服务(如 go-zero, kratos)和互联网大厂的写法。

  • 代码逻辑:

    1. infra 负责生成 *gorm.DB 并返回。
    2. repository 定义一个结构体,把 *gorm.DB 存进去。
    3. logic 调用 repository 的实例。
  • 代码示例:

    复制代码
    // internal/repository/user_repo.go
    type UserRepo struct {
        db *gorm.DB // 私有变量,不暴露给外面
    }
    
    // 构造函数,创建 Repo 时必须传入 DB
    func NewUserRepo(db *gorm.DB) *UserRepo {
        return &UserRepo{db: db}
    }
    
    func (r *UserRepo) FindByID(id uint) (*model.User, error) {
        var user model.User
        err := r.db.First(&user, id).Error
        return &user, err
    }

3. 为什么推荐"结构体注入"?

  1. 链路清晰:你在 main.go 启动时就能一眼看出:DB 传给了 Repo,Repo 传给了 Logic。
  2. 方便做"假"测试(Mock):写单元测试时,你可以传一个模拟的 DB 进去,而不需要真的连数据库。
  3. 支持多库:如果你以后业务大了,读写分离或者有多个库,你只需要在初始化时传入不同的 DB 实例即可,逻辑层代码一行都不用改。

4. 结合你之前的架构:如何串联起来?

如果你打算采用推荐的写法,你的 main.go 启动流程大致如下:

  1. 加载配置:cfg := config.Load()
  2. 初始化基础设施:db := infra.NewDB(cfg) (返回 *gorm.DB)
  3. 创建 Repository:userRepo := repository.NewUserRepo(db)
  4. 创建 Logic:userLogic := logic.NewUserLogic(userRepo)
  5. 注册 Handler:r.POST("/user", handler.NewUserHandler(userLogic))

相关推荐
妙码生花3 天前
从 PHP 到 AI + Golang,程序员自救转型手记(八):设计管理员模型、热重载配置
前端·后端·go
tyung4 天前
Go 手写 Wait-Free MPSC 无界队列:SwapPointer 实现多生产者无锁入队
后端·go
陈明勇4 天前
Go 1.26 新特性回顾:语言增强、工具升级与 Green Tea GC 默认启用
后端·go
妙码生花5 天前
从 PHP 到 AI + Golang,程序员自救转型手记(二):目录结构、初始化 GIT、设计并开发配置系统
前端·后端·go
leeyi5 天前
Deer-Go:字节 Deer-Flow 的 Go 移植,深度研究 Agent 全拆解
go·aigc·agent
Bolt6 天前
TypeScript 7.0 来了:当 tsc 用 Go 重写之后
javascript·typescript·go
Go_error6 天前
Datatypes:Go 轻松支持数据库JSON类型
后端·go
任沫7 天前
Agent之Function Call
javascript·人工智能·go
唐青枫7 天前
别再把 interface 当万能盒子:Go 接口从隐式实现到项目解耦
go
tyung10 天前
Go 手写有界 SPSC 环形队列:无 CAS、无锁、Cache 友好的无锁模型
后端·go