GO分层架构【2】使用GIN与GORM

现在大家都使用的的GIN和GORM开发架构是怎么样的?

目前在 Go 社区中,基于 Gin 和 GORM 的主流微服务开发架构,最推崇的是 "工程化分层"。它在你的基础上,通过引入 Logic/Service 层 和 Repository 层,彻底解决代码臃肿和难以测试的问题。

以下是目前最流行的标准架构拆解:

1. 核心分层架构图

数据流向遵循:请求 → Handler → Logic → Repository → Database。

复制代码
internal/
├── handler/       # (入口层) 负责 Gin 的参数绑定、简单校验、返回 JSON
├── logic/         # (业务层) 核心是大脑!组合业务步骤,不涉及具体 SQL
├── repository/    # (持久层) 只有这里出现 GORM,负责具体的增删改查
├── model/         # (模型层) 定义 GORM 结构体(Table Schema)
└── middleware/    # (中间件) 权限校验、日志记录

2. 各层代码示例(以"用户充值"为例)

第一层:model (定义表结构)

复制代码
package model

type User struct {
    ID      uint   `gorm:"primaryKey"`
    Balance int64  `gorm:"column:balance"` // 余额
}

第二层:repository (数据操作 - 只有它认识 GORM)

复制代码
package repository

import "your-project/internal/model"
import "gorm.io/gorm"

type UserRepo struct {
    db *gorm.DB
}

func (r *UserRepo) UpdateBalance(id uint, amount int64) error {
    // 纯粹的数据库操作
    return r.db.Model(&model.User{}).Where("id = ?", id).
        Update("balance", gorm.Expr("balance + ?", amount)).Error
}

第三层:logic (业务核心 - 这里处理复杂逻辑)

复制代码
package logic

import "your-project/internal/repository"

type UserLogic struct {
    repo *repository.UserRepo
}

func (l *UserLogic) Recharge(userId uint, money int64) error {
    // 1. 这里处理业务规则:比如充值不能小于 0
    if money <= 0 { return errors.New("金额错误") }
    
    // 2. 调用数据层
    return l.repo.UpdateBalance(userId, money)
}

第四层:handler (Gin 入口 - 只管翻译)

复制代码
package handler

import "your-project/pkg/res" // 你之前定义的统一返回

func RechargeHandler(c *gin.Context) {
    var req struct { UserId uint; Amount int64 }
    c.ShouldBindJSON(&req) // 参数解析

    // 调用 Logic 层
    err := logic.NewUserLogic().Recharge(req.UserId, req.Amount)

    if err != nil {
        c.JSON(200, res.Error(500, err.Error()))
        return
    }
    c.JSON(200, res.Success(nil)) // 统一格式返回
}

3. 为什么这是主流?

  1. GORM 不外溢:GORM 的代码只出现在 repository 或 infra。如果你哪天想换 sqlx 或 ent,只需要改底层,不需要动 logic 和 handler。
  2. Logic 层可复用:
    • API 调用:通过 handler 调 logic。
    • 定时任务:通过 cron 调 logic。
    • 自检脚本:通过 test/client 调 logic。
  3. 并发安全与事务:主流做法是在 logic 层通过闭包或 Context 处理事务,确保业务的原子性。

4. 针对你现状的调整建议

  • 将 infra 细化:你现在的 infra 可能只是初始化 DB 连接。建议在 infra 下建一个 repository 子目录,专门写 GORM 的查询。
  • 增加 logic 文件夹:把你 handler 里那些复杂的 if-else、计算、多步 SQL 写入全部挪到 logic 里。
  • 统一返回:继续使用你放在 pkg/res 下的结构体,这是非常地道的做法。

避坑指南:在 GORM 开发中,千万不要把 *gin.Context 传进 logic 层或数据库层,这会导致你的业务逻辑和 HTTP 框架死死锁定。

相关推荐
梦想不只是梦与想11 小时前
HarmonyOS应用分层架构设计
harmonyos·分层架构·一次开发,多端部署
我的div丢了肿么办2 天前
go语言中管道 channel的使用
后端·go
海宇数科2 天前
Go数据工程:利用海宇婚恋风险报告优化实名制严肃婚恋交友合规体验
人工智能·go
用户125758524362 天前
Golang Web后台管理框架推荐:Gin、GoFrame与数据面板项目怎么分
go
我的div丢了肿么办2 天前
进程和线程以及go语言中的协程
后端·go
福兮说3 天前
Go time 包的九个坑:== 判断相等、Parse 差 8 小时、1 月 31 日加一个月变成 3 月 3 日
go
我的div丢了肿么办4 天前
go语言中的空接口和类型断言
后端·go
Thinker QAQ4 天前
并发编程(七):volatile——从语言规则到 CPU
java·python·go·并发编程·volatile·memory model
ZealSinger4 天前
Go1.25 FlightRecorder慢请求截trace
网络·数据库·go
福兮说4 天前
Go 迭代器的七个坑:break 后 panic、一次性迭代器、iter.Pull 不 stop,还有一个跑错地方的 defer
go