🏷️ 标签: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"
}
六、项目亮点(企业级规范)
- 分层架构 :
model→dao→api→route,职责清晰 - 统一响应:所有接口返回格式一致,前端易于处理
- GORM 最佳实践:连接池、软删除、钩子函数、参数绑定
- Gin 标准用法:路由分组、参数校验、路径参数
- 生产可用:可直接扩展中间件、JWT、日志、配置文件
七、常见问题与避坑
- 数据库连接失败:检查 MySQL 服务、账号密码、库名
- 无法解析时间 :确保
ParseTime=true - 软删除不生效 :模型必须包含
gorm.DeletedAt字段 - 跨域问题:可添加 Gin 跨域中间件
- 空指针 panic :
email等可空字段必须使用*string
八、总结
本文基于Gin + GORM V2 + MySQL 实现了一套完整的企业级 Go 后端 API 项目,包含:
- 标准项目结构
- 数据库连接与连接池
- 完整 CRUD
- 统一响应格式
- 生产级代码规范
非常适合 Go 新手入门、毕业设计、快速开发中小型后台服务。
版权声明
本文为原创 Go 后端技术文章,CSDN 首发,Gin + GORM 实战教程,代码可直接复制使用,禁止未经授权转载、抄袭。