Go 后端实战|Gin + GORM V2 + MySQL 企业级 API 项目开发(完整版)

🏷️ 标签:Go Gin GORM V2 MySQL Web框架 API开发 Go后端📝 适用人群:Go 后端新手、想快速开发 API 的开发者、毕业设计 / 项目实战学习者💡 核心亮点:全程实战无废话,从环境搭建到生产级项目封装,代码可直接复制运行,标准企业项目结构,适配 CSDN 发布

一、前言

在 Go 后端开发中,Gin + GORM 是目前最主流、最高效的技术组合:

  • Gin:Go 生态性能最强、使用最广的 Web 框架,主打高性能、极简 API 开发,内置路由、中间件、参数绑定等核心能力
  • GORM V2:成熟稳定的 ORM 框架,专注数据库操作,无需手写 SQL
  • MySQL:最常用的关系型数据库

本文带你从零搭建Gin + GORM + MySQL 生产级项目,实现完整的用户 CRUD API 接口,代码可直接用于毕设、企业项目,也可一键发布到 CSDN。

二、环境准备

2.1 依赖安装

执行以下命令安装所有核心依赖:

复制代码
# 1. 安装Gin Web框架
go get github.com/gin-gonic/gin

# 2. 安装GORM V2
go get gorm.io/gorm

# 3. 安装MySQL驱动
go get gorm.io/driver/mysql

2.2 MySQL 数据表创建

执行 SQL 创建user表(支持软删除、自动时间戳):

复制代码
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '用户名',
  `age` int NOT NULL COMMENT '年龄',
  `email` varchar(64) DEFAULT NULL COMMENT '邮箱',
  `created_at` datetime NOT NULL COMMENT '创建时间',
  `updated_at` datetime NOT NULL COMMENT '更新时间',
  `deleted_at` datetime DEFAULT NULL COMMENT '软删除时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

三、生产级项目结构(企业标准)

复制代码
gin-gorm-demo/
├── config/          # 配置文件
│   └── db.go        # MySQL配置
├── db/              # 数据库初始化
│   └── mysql.go     # GORM连接、连接池
├── model/           # 数据模型
│   └── user.go      # 用户模型+钩子
├── dao/             # 数据访问层(数据库操作)
│   └── user.go      # CRUD封装
├── api/             # API接口层(Handler)
│   └── user.go      # 用户接口
├── route/           # 路由注册
│   └── route.go     # Gin路由
├── common/          # 公共工具
│   └── response.go  # 统一返回格式
├── go.mod           # 依赖管理
└── main.go          # 项目入口

四、代码实现(全可复制)

4.1 go.mod

复制代码
module gin-gorm-demo

go 1.21

require (
	github.com/gin-gonic/gin v1.9.1
	gorm.io/driver/mysql v1.5.2
	gorm.io/gorm v1.25.4
)

4.2 config/db.go 数据库配置

复制代码
package config

import "time"

type MySQLConfig struct {
	User     string
	Passwd   string
	Host     string
	Port     string
	DBName   string
	Charset  string
	ParseTime bool
	Loc      string

	MaxOpenConns    int
	MaxIdleConns    int
	ConnMaxLifetime time.Duration
	ConnMaxIdleTime time.Duration
}

func DefaultMySQLConfig() *MySQLConfig {
	return &MySQLConfig{
		User:            "root",
		Passwd:          "root",
		Host:            "127.0.0.1",
		Port:            "3306",
		DBName:          "testdb",
		Charset:         "utf8mb4",
		ParseTime:       true,
		Loc:             "Local",
		MaxOpenConns:    20,
		MaxIdleConns:    10,
		ConnMaxLifetime: 3 * time.Minute,
		ConnMaxIdleTime: 1 * time.Minute,
	}
}

func (c *MySQLConfig) DSN() string {
	return c.User + ":" + c.Passwd + "@tcp(" + c.Host + ":" + c.Port + ")/" +
		c.DBName + "?charset=" + c.Charset + "&parseTime=" + bool2Str(c.ParseTime) + "&loc=" + c.Loc
}

func bool2Str(b bool) string {
	if b {
		return "true"
	}
	return "false"
}

4.3 db/mysql.go GORM 初始化

复制代码
package db

import (
	"gin-gorm-demo/config"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"time"
)

var DB *gorm.DB

func InitMySQL() error {
	cfg := config.DefaultMySQLConfig()
	var err error
	DB, err = gorm.Open(mysql.Open(cfg.DSN()), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info),
	})
	if err != nil {
		return err
	}

	sqlDB, err := DB.DB()
	if err != nil {
		return err
	}
	sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
	sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
	sqlDB.SetConnMaxLifetime(cfg.ConnMaxLifetime)
	sqlDB.SetConnMaxIdleTime(cfg.ConnMaxIdleTime)

	err = sqlDB.Ping()
	if err != nil {
		return err
	}
	log.Println("✅ MySQL 连接成功")
	return nil
}

4.4 model/user.go 数据模型

复制代码
package model

import (
	"errors"
	"gorm.io/gorm"
	"time"
)

type User struct {
	ID        int            `gorm:"primaryKey;autoIncrement"`
	Name      string         `gorm:"type:varchar(32);not null"`
	Age       int            `gorm:"type:int;not null"`
	Email     *string        `gorm:"type:varchar(64)"`
	CreatedAt time.Time      `gorm:"type:datetime"`
	UpdatedAt time.Time      `gorm:"type:datetime"`
	DeletedAt gorm.DeletedAt `gorm:"index"`
}

func (u *User) TableName() string {
	return "user"
}

// 新增前校验年龄
func (u *User) BeforeCreate(tx *gorm.DB) error {
	if u.Age < 0 || u.Age > 150 {
		return errors.New("年龄必须在0-150之间")
	}
	return nil
}

4.5 common/response.go 统一响应

复制代码
package common

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

type Response struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data,omitempty"`
}

// Success 成功返回
func Success(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, Response{
		Code: 200,
		Msg:  "success",
		Data: data,
	})
}

// Error 失败返回
func Error(c *gin.Context, msg string) {
	c.JSON(http.StatusOK, Response{
		Code: 500,
		Msg:  msg,
	})
}

4.6 dao/user.go 数据库操作

复制代码
package dao

import (
	"gin-gorm-demo/db"
	"gin-gorm-demo/model"
)

// AddUser 新增用户
func AddUser(user *model.User) error {
	return db.DB.Create(user).Error
}

// GetUserByID 根据ID查询
func GetUserByID(id int) (*model.User, error) {
	var user model.User
	err := db.DB.First(&user, id).Error
	return &user, err
}

// ListUser 用户列表
func ListUser(page, pageSize int) ([]model.User, int64, error) {
	var users []model.User
	var total int64
	db.DB.Model(&model.User{}).Count(&total)
	err := db.DB.Offset((page - 1) * pageSize).Limit(pageSize).Find(&users).Error
	return users, total, err
}

// UpdateUser 更新用户
func UpdateUser(id int, data map[string]interface{}) error {
	return db.DB.Model(&model.User{}).Where("id=?", id).Updates(data).Error
}

// DeleteUser 删除用户
func DeleteUser(id int) error {
	return db.DB.Delete(&model.User{}, id).Error
}

4.7 api/user.go API 接口

复制代码
package api

import (
	"gin-gorm-demo/common"
	"gin-gorm-demo/dao"
	"gin-gorm-demo/model"
	"github.com/gin-gonic/gin"
	"strconv"
)

// AddUser 新增用户
func AddUser(c *gin.Context) {
	var user model.User
	if err := c.ShouldBindJSON(&user); err != nil {
		common.Error(c, "参数错误:"+err.Error())
		return
	}
	if err := dao.AddUser(&user); err != nil {
		common.Error(c, "新增失败:"+err.Error())
		return
	}
	common.Success(c, user)
}

// GetUser 获取单个用户
func GetUser(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	user, err := dao.GetUserByID(id)
	if err != nil {
		common.Error(c, "查询失败:"+err.Error())
		return
	}
	common.Success(c, user)
}

// ListUser 用户列表
func ListUser(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	users, total, err := dao.ListUser(page, pageSize)
	if err != nil {
		common.Error(c, "查询失败")
		return
	}
	common.Success(c, gin.H{"list": users, "total": total})
}

// UpdateUser 更新用户
func UpdateUser(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var data map[string]interface{}
	if err := c.ShouldBindJSON(&data); err != nil {
		common.Error(c, "参数错误")
		return
	}
	if err := dao.UpdateUser(id, data); err != nil {
		common.Error(c, "更新失败")
		return
	}
	common.Success(c, nil)
}

// DeleteUser 删除用户
func DeleteUser(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	if err := dao.DeleteUser(id); err != nil {
		common.Error(c, "删除失败")
		return
	}
	common.Success(c, nil)
}

4.8 route/route.go 路由配置

复制代码
package route

import (
	"gin-gorm-demo/api"
	"github.com/gin-gonic/gin"
)

func InitRouter() *gin.Engine {
	r := gin.Default()

	// 用户CRUD接口
	userGroup := r.Group("/user")
	{
		userGroup.POST("", api.AddUser)       // 新增
		userGroup.GET("/:id", api.GetUser)    // 查询单个
		userGroup.GET("/list", api.ListUser)  // 列表
		userGroup.PUT("/:id", api.UpdateUser) // 更新
		userGroup.DELETE("/:id", api.DeleteUser) // 删除
	}

	return r
}

4.9 main.go 项目入口

复制代码
package main

import (
	"gin-gorm-demo/db"
	"gin-gorm-demo/route"
	"log"
)

func main() {
	// 初始化数据库
	if err := db.InitMySQL(); err != nil {
		log.Fatal("数据库连接失败:", err)
	}

	// 初始化路由
	r := route.InitRouter()

	// 启动服务
	log.Println("🚀 Gin服务启动:http://127.0.0.1:8080")
	_ = r.Run(":8080")
}

五、接口测试(Postman 可直接用)

接口地址 请求方式 功能
/user POST 新增用户
/user/1 GET 获取 ID=1 用户
/user/list?page=1 GET 分页列表
/user/1 PUT 更新用户
/user/1 DELETE 删除用户

新增用户请求体示例

复制代码
{
    "name": "张三",
    "age": 20,
    "email": "zhangsan@qq.com"
}

六、项目亮点(企业级规范)

  1. 分层架构modeldaoapiroute,职责清晰
  2. 统一响应:所有接口返回格式一致,前端易于处理
  3. GORM 最佳实践:连接池、软删除、钩子函数、参数绑定
  4. Gin 标准用法:路由分组、参数校验、路径参数
  5. 生产可用:可直接扩展中间件、JWT、日志、配置文件

七、常见问题与避坑

  1. 数据库连接失败:检查 MySQL 服务、账号密码、库名
  2. 无法解析时间 :确保ParseTime=true
  3. 软删除不生效 :模型必须包含gorm.DeletedAt字段
  4. 跨域问题:可添加 Gin 跨域中间件
  5. 空指针 panicemail等可空字段必须使用*string

八、总结

本文基于Gin + GORM V2 + MySQL 实现了一套完整的企业级 Go 后端 API 项目,包含:

  • 标准项目结构
  • 数据库连接与连接池
  • 完整 CRUD
  • 统一响应格式
  • 生产级代码规范

非常适合 Go 新手入门、毕业设计、快速开发中小型后台服务。


版权声明

本文为原创 Go 后端技术文章,CSDN 首发,Gin + GORM 实战教程,代码可直接复制使用,禁止未经授权转载、抄袭。

相关推荐
Hical_W1 小时前
Hical 踩坑实录五部曲(五):Boost.MySQL 协程集成的 5 个坑
数据库·mysql·开源
XMYX-01 小时前
28 - Go JSON 数据操作
开发语言·golang·json
czlczl200209252 小时前
mysql表复制方案
数据库·mysql
jran-5 小时前
MySQL多表操作 查询&子查询&外键约束
数据库·mysql
jieyucx5 小时前
Go 语言核心关键字:defer 深度解析与实战避坑
开发语言·后端·golang·defer
看到代码头都是大的6 小时前
CentoOS7安装mysql 8.0.46
mysql
阿坤带你走近大数据8 小时前
DM达梦数据库的介绍
数据库·mysql·oracle·国产信创
Wy_编程9 小时前
Go语言中的指针
开发语言·后端·golang
lolo大魔王9 小时前
Go语言数据库操作之GORM框架从入门到生产实战(完整版)
开发语言·数据库·golang