【web3基础】Go-Zero+mysql进行crud操作(三)

Go-Zero+mysql进行crud操作

    • 目录
    • 一、项目概述
      • [1.1 项目背景](#1.1 项目背景)
      • [1.2 项目目标](#1.2 项目目标)
    • 二、整体流程图
    • 三、环境准备
      • [3.1 安装 Go](#3.1 安装 Go)
      • [3.2 安装 go-zero 和 goctl](#3.2 安装 go-zero 和 goctl)
      • [3.3 安装 MySQL](#3.3 安装 MySQL)
    • 四、详细步骤
      • [4.1 创建项目](#4.1 创建项目)
      • [4.2 配置数据库连接](#4.2 配置数据库连接)
        • [4.2.1 修改配置文件](#4.2.1 修改配置文件)
        • [4.2.2 修改配置结构体](#4.2.2 修改配置结构体)
      • [4.3 编写 API 文件](#4.3 编写 API 文件)
      • [4.4 生成 API 代码](#4.4 生成 API 代码)
      • [4.5 生成 Model 层](#4.5 生成 Model 层)
        • [4.5.1 准备 SQL 文件](#4.5.1 准备 SQL 文件)
        • [4.5.2 在数据库中执行 SQL](#4.5.2 在数据库中执行 SQL)
        • [4.5.3 生成 Model 代码](#4.5.3 生成 Model 代码)
      • [4.6 注册 Model 到服务上下文](#4.6 注册 Model 到服务上下文)
      • [4.7 编写业务逻辑](#4.7 编写业务逻辑)
        • [4.7.1 实现创建用户逻辑](#4.7.1 实现创建用户逻辑)
        • [4.7.2 实现查询用户逻辑](#4.7.2 实现查询用户逻辑)
        • [4.7.3 实现更新用户逻辑](#4.7.3 实现更新用户逻辑)
        • [4.7.4 实现删除用户逻辑](#4.7.4 实现删除用户逻辑)
      • [4.8 常见问题与解决](#4.8 常见问题与解决)
        • [问题 1: field "name" is not set](#问题 1: field "name" is not set)
        • [问题 2: sql: Scan error on column index X, name "created_at"](#问题 2: sql: Scan error on column index X, name "created_at")
        • [问题 3: 连接数据库失败](#问题 3: 连接数据库失败)
      • [4.9 测试验证](#4.9 测试验证)
        • [4.9.1 启动服务](#4.9.1 启动服务)
        • [4.9.2 测试创建用户](#4.9.2 测试创建用户)
        • [4.9.3 测试查询用户](#4.9.3 测试查询用户)
        • [4.9.4 测试更新用户](#4.9.4 测试更新用户)
        • [4.9.5 测试删除用户](#4.9.5 测试删除用户)
    • 五、项目结构说明
    • 六、总结
      • [6.1 开发流程回顾](#6.1 开发流程回顾)
      • [6.2 关键命令速查](#6.2 关键命令速查)

本文详细介绍如何从零开始搭建一个基于 go-zero 框架的 RESTful API 项目,实现用户的增删改查功能。

关键词: Go-Zero, MySQL, RESTful API, 微服务, Go 语言, 数据库连接, CRUD 操作, goctl 工具

目录

  • 一、项目概述
  • 二、整体流程图
  • 三、环境准备
  • 四、详细步骤
    • [4.1 创建项目](#4.1 创建项目)
    • [4.2 配置数据库连接](#4.2 配置数据库连接)
    • [4.3 编写 API 文件](#4.3 编写 API 文件)
    • [4.4 生成 API 代码](#4.4 生成 API 代码)
    • [4.5 生成 Model 层](#4.5 生成 Model 层)
    • [4.6 注册 Model 到服务上下文](#4.6 注册 Model 到服务上下文)
    • [4.7 编写业务逻辑](#4.7 编写业务逻辑)
    • [4.8 常见问题与解决](#4.8 常见问题与解决)
    • [4.9 测试验证](#4.9 测试验证)
  • 五、项目结构说明
  • 六、总结

一、项目概述

1.1 项目背景

go-zero 是一个集成了各种工程实践的 Web 和 RPC 框架,具有以下特点:

  • 简单易用:通过 goctl 工具一键生成代码
  • 微服务架构:原生支持微服务设计
  • 高性能:内置限流、熔断、负载均衡等功能
  • 代码规范:统一的代码结构和风格

1.2 项目目标

实现一个用户管理 RESTful API,包含以下接口:

方法 路径 功能
POST /api/users 创建用户
GET /api/users 查询用户
PUT /api/users 更新用户
DELETE /api/users 删除用户

二、整体流程图

三、环境准备

3.1 安装 Go

确保已安装 Go 1.19+:

bash 复制代码
go version

3.2 安装 go-zero 和 goctl

bash 复制代码
# 安装 go-zero 框架
go install github.com/zeromicro/go-zero/latest@latest

# 安装 goctl 代码生成工具
go install github.com/zeromicro/go-zero/tools/goctl@latest

# 验证安装
goctl --version

3.3 安装 MySQL

确保 MySQL 服务正常运行,并创建好数据库:

sql 复制代码
CREATE DATABASE test_demo DEFAULT CHARACTER SET utf8mb4;

四、详细步骤

4.1 创建项目

使用 goctl 创建新的 API 项目:

bash 复制代码
# 创建项目
goctl api new mysqldemo

# 进入项目目录
cd mysqldemo

生成的初始项目结构:

复制代码
mysqldemo/
├── etc/
│   └── user-api.yaml        # 配置文件
├── internal/
│   ├── config/              # 配置结构体
│   ├── handler/             # HTTP 处理器
│   ├── logic/               # 业务逻辑
│   ├── model/               # 数据模型(初始为空)
│   ├── svc/                 # 服务上下文
│   └── types/               # 类型定义
├── user.api                 # API 定义文件
└── user.go                  # 入口文件

4.2 配置数据库连接

4.2.1 修改配置文件

编辑 etc/user-api.yaml,添加 MySQL 数据源配置:

yaml 复制代码
Name: mysqldemo-api
Host: 0.0.0.0
Port: 8888

Mysql:
  DataSource: root:your_password@tcp(127.0.0.1:3306)/test_demo?charset=utf8mb4&parseTime=true

重要提示:

必须添加 parseTime=true 参数,否则时间字段会报错:

复制代码
❌ 错误: parseTime-true  (使用了横线)
✅ 正确: parseTime=true  (使用等号)
4.2.2 修改配置结构体

编辑 internal/config/config.go,添加 MySQL 配置字段:

go 复制代码
package config

import "github.com/zeromicro/go-zero/rest"

type Config struct {
    rest.RestConf
    
    Mysql struct {
        DataSource string
    }
}

4.3 编写 API 文件

编辑 user.api 文件,定义 API 接口:

go 复制代码
// user.api

type (
    // 用户实体
    User {
        Id        int64  `json:"id"`
        Name      string `json:"name"`
        Age       int    `json:"age"`
        Email     string `json:"email"`
        CreatedAt string `json:"createdAt,optional"`
        UpdatedAt string `json:"updatedAt,optional"`
    }
    
    // 创建用户请求
    UserCreateReq {
        Name  string `json:"name"`           // 必填字段
        Age   int    `json:"age,optional"`   // 可选字段
        Email string `json:"email"`           // 必填字段
    }
    
    // 更新用户请求
    UserUpdateReq {
        Id    int64  `json:"id"`
        Name  string `json:"name,optional"`
        Age   int    `json:"age,optional"`
        Email string `json:"email,optional"`
    }
    
    // 查询用户请求
    UserQueryReq {
        Id    int64  `form:"id,optional"`
        Email string `form:"email,optional"`
    }
    
    // 统一响应结构
    Response {
        Code    int         `json:"code"`
        Message string      `json:"message"`
        Data    interface{} `json:"data,optional"`
    }
)

service user-api {
    @handler createUser
    post /api/users (UserCreateReq) returns (Response)
    
    @handler getUser
    get /api/users (UserQueryReq) returns (Response)
    
    @handler updateUser
    put /api/users (UserUpdateReq) returns (Response)
    
    @handler deleteUser
    delete /api/users (UserQueryReq) returns (Response)
}

注意事项:

  1. json:"name" - 必填字段,不带 optional
  2. json:"age,optional" - 可选字段,带 optional 标签
  3. form:"id" - GET/DELETE 请求使用 form 标签
  4. json:"id" - POST/PUT 请求使用 json 标签

4.4 生成 API 代码

根据 API 文件生成代码:

bash 复制代码
goctl api go -api user.api -dir .

生成内容说明:

目录 说明
internal/handler/ HTTP 处理器,负责解析请求和返回响应
internal/logic/ 业务逻辑层,实现具体功能(框架已生成,需填充逻辑)
internal/types/ 请求/响应类型定义
internal/config/ 配置结构体(已在步骤 4.2 修改)
internal/svc/ 服务上下文(需在步骤 4.6 修改)

4.5 生成 Model 层

4.5.1 准备 SQL 文件

sql/user.sql 中定义表结构:

sql 复制代码
CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL COMMENT '用户姓名',
  `age` int DEFAULT NULL COMMENT '用户年龄',
  `email` varchar(255) DEFAULT NULL COMMENT '用户邮箱',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
4.5.2 在数据库中执行 SQL
bash 复制代码
mysql -u root -p test_demo < sql/user.sql
4.5.3 生成 Model 代码

使用 goctl 从 SQL 文件生成 Model:

bash 复制代码
goctl model mysql ddl -src sql/user.sql -dir internal/model -c=false

参数说明:

  • -src sql/user.sql:指定 SQL 文件路径
  • -dir internal/model:指定 Model 输出目录
  • -c=false:不生成缓存代码(简单场景可关闭)

生成的 Model 文件:

复制代码
internal/model/
├── usermodel.go        # 自定义扩展方法(可编辑)
├── usermodel_gen.go    # 自动生成的基础方法(勿修改)
└── vars.go             # 错误变量定义

usermodel_gen.go 自动生成的接口:

go 复制代码
type userModel interface {
    Insert(ctx context.Context, data *User) (sql.Result, error)
    FindOne(ctx context.Context, id int64) (*User, error)
    FindOneByEmail(ctx context.Context, email string) (*User, error)
    Update(ctx context.Context, data *User) error
    Delete(ctx context.Context, id int64) error
}

4.6 注册 Model 到服务上下文

编辑 internal/svc/servicecontext.go,初始化数据库连接和 UserModel:

go 复制代码
package svc

import (
    "mysqldemo/internal/config"
    "mysqldemo/internal/model"
    
    "github.com/zeromicro/go-zero/core/stores/sqlx"
)

type ServiceContext struct {
    Config    config.Config
    UserModel model.UserModel
}

func NewServiceContext(c config.Config) *ServiceContext {
    // 创建数据库连接
    conn := sqlx.NewMysql(c.Mysql.DataSource)
    
    return &ServiceContext{
        Config:    c,
        UserModel: model.NewUserModel(conn),
    }
}

4.7 编写业务逻辑

4.7.1 实现创建用户逻辑

编辑 internal/logic/createuserlogic.go

go 复制代码
package logic

import (
    "context"
    
    "mysqldemo/internal/model"
    "mysqldemo/internal/svc"
    "mysqldemo/internal/types"
    
    "github.com/zeromicro/go-zero/core/logx"
)

type CreateUserLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserLogic {
    return &CreateUserLogic{
        Logger: logx.WithContext(ctx),
        ctx:    ctx,
        svcCtx: svcCtx,
    }
}

func (l *CreateUserLogic) CreateUser(req *types.UserCreateReq) (*types.Response, error) {
    // 构建用户对象
    user := &model.User{
        Name:  req.Name,
        Age:   req.Age,
        Email: req.Email,
    }
    
    // 调用 Model 层插入数据
    res, err := l.svcCtx.UserModel.Insert(l.ctx, user)
    if err != nil {
        return nil, err
    }
    
    // 获取自增 ID
    id, err := res.LastInsertId()
    if err != nil {
        return nil, err
    }
    
    return &types.Response{
        Code:    200,
        Message: "success",
        Data:    map[string]interface{}{"id": id},
    }, nil
}
4.7.2 实现查询用户逻辑

编辑 internal/logic/getuserlogic.go

go 复制代码
package logic

import (
    "context"
    
    "mysqldemo/internal/model"
    "mysqldemo/internal/svc"
    "mysqldemo/internal/types"
    
    "github.com/zeromicro/go-zero/core/logx"
)

type GetUserLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
    return &GetUserLogic{
        Logger: logx.WithContext(ctx),
        ctx:    ctx,
        svcCtx: svcCtx,
    }
}

func (l *GetUserLogic) GetUser(req *types.UserQueryReq) (*types.Response, error) {
    var user *model.User
    var err error
    
    // 支持按 ID 或 Email 查询
    if req.Id > 0 {
        user, err = l.svcCtx.UserModel.FindOne(l.ctx, req.Id)
    } else if req.Email != "" {
        user, err = l.svcCtx.UserModel.FindOneByEmail(l.ctx, req.Email)
    } else {
        return &types.Response{
            Code:    400,
            Message: "参数错误,请提供 id 或 email",
        }, nil
    }
    
    if err != nil {
        if err == model.ErrNotFound {
            return &types.Response{
                Code:    404,
                Message: "用户不存在",
            }, nil
        }
        return nil, err
    }
    
    return &types.Response{
        Code:    200,
        Message: "success",
        Data:    user,
    }, nil
}
4.7.3 实现更新用户逻辑

编辑 internal/logic/updateuserlogic.go

go 复制代码
package logic

import (
    "context"
    
    "mysqldemo/internal/model"
    "mysqldemo/internal/svc"
    "mysqldemo/internal/types"
    
    "github.com/zeromicro/go-zero/core/logx"
)

type UpdateUserLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserLogic {
    return &UpdateUserLogic{
        Logger: logx.WithContext(ctx),
        ctx:    ctx,
        svcCtx: svcCtx,
    }
}

func (l *UpdateUserLogic) UpdateUser(req *types.UserUpdateReq) (*types.Response, error) {
    // 先查询用户是否存在
    user, err := l.svcCtx.UserModel.FindOne(l.ctx, req.Id)
    if err != nil {
        if err == model.ErrNotFound {
            return &types.Response{
                Code:    404,
                Message: "用户不存在",
            }, nil
        }
        return nil, err
    }
    
    // 更新字段(只更新非空字段)
    if req.Name != "" {
        user.Name = req.Name
    }
    if req.Age > 0 {
        user.Age = req.Age
    }
    if req.Email != "" {
        user.Email = req.Email
    }
    
    // 执行更新
    err = l.svcCtx.UserModel.Update(l.ctx, user)
    if err != nil {
        return nil, err
    }
    
    return &types.Response{
        Code:    200,
        Message: "更新成功",
        Data:    user,
    }, nil
}
4.7.4 实现删除用户逻辑

编辑 internal/logic/deleteuserlogic.go

go 复制代码
package logic

import (
    "context"
    
    "mysqldemo/internal/svc"
    "mysqldemo/internal/types"
    
    "github.com/zeromicro/go-zero/core/logx"
)

type DeleteUserLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewDeleteUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteUserLogic {
    return &DeleteUserLogic{
        Logger: logx.WithContext(ctx),
        ctx:    ctx,
        svcCtx: svcCtx,
    }
}

func (l *DeleteUserLogic) DeleteUser(req *types.UserQueryReq) (*types.Response, error) {
    // 删除用户
    err := l.svcCtx.UserModel.Delete(l.ctx, req.Id)
    if err != nil {
        return nil, err
    }
    
    return &types.Response{
        Code:    200,
        Message: "删除成功",
    }, nil
}

4.8 常见问题与解决

问题 1: field "name" is not set

原因 :请求没有正确设置 Content-Type: application/json

解决:确保 curl 命令包含请求头:

bash 复制代码
curl -X POST http://127.0.0.1:8888/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","age":25,"email":"zhangsan@example.com"}'
问题 2: sql: Scan error on column index X, name "created_at"

原因 :数据库连接字符串缺少 parseTime=true 参数

解决 :修改 etc/user-api.yaml

yaml 复制代码
# 错误 ❌
DataSource: root:password@tcp(127.0.0.1:3306)/test_demo?charset=utf8mb4&parseTime-true

# 正确 ✅
DataSource: root:password@tcp(127.0.0.1:3306)/test_demo?charset=utf8mb4&parseTime=true
问题 3: 连接数据库失败

排查步骤

  1. 检查 MySQL 服务是否启动
  2. 检查用户名、密码是否正确
  3. 检查数据库是否存在
  4. 检查网络连接和防火墙设置

4.9 测试验证

4.9.1 启动服务
bash 复制代码
go run user.go -f etc/user-api.yaml

输出:

复制代码
Starting server at 0.0.0.0:8888...
4.9.2 测试创建用户
bash 复制代码
curl -X POST http://127.0.0.1:8888/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"刘德华","age":35,"email":"dehua@163.com"}'

响应:

json 复制代码
{
  "code": 200,
  "message": "success",
  "data": {"id": 1}
}
4.9.3 测试查询用户

按 ID 查询:

bash 复制代码
curl "http://127.0.0.1:8888/api/users?id=1"

响应:

json 复制代码
{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "name": "刘德华",
    "age": 35,
    "email": "dehua@163.com",
    "createdAt": "2025-07-19T07:00:00Z",
    "updatedAt": "2025-07-19T07:00:00Z"
  }
}

按 Email 查询:

bash 复制代码
curl "http://127.0.0.1:8888/api/users?email=dehua@163.com"
4.9.4 测试更新用户
bash 复制代码
curl -X PUT http://127.0.0.1:8888/api/users \
  -H "Content-Type: application/json" \
  -d '{"id":1,"name":"刘德虎","age":36}'

响应:

json 复制代码
{
  "code": 200,
  "message": "更新成功",
  "data": {
    "id": 1,
    "name": "刘德虎",
    "age": 36,
    "email": "dehua@163.com"
  }
}
4.9.5 测试删除用户
bash 复制代码
curl -X DELETE "http://127.0.0.1:8888/api/users?id=1"

响应:

json 复制代码
{
  "code": 200,
  "message": "删除成功"
}

五、项目结构说明

复制代码
mysqldemo/
├── etc/
│   └── user-api.yaml          # 配置文件
├── internal/
│   ├── config/
│   │   └── config.go          # 配置结构体
│   ├── handler/
│   │   ├── routes.go          # 路由注册
│   │   ├── createuserhandler.go
│   │   ├── getuserhandler.go
│   │   ├── updateuserhandler.go
│   │   └── deleteuserhandler.go
│   ├── logic/
│   │   ├── createuserlogic.go  # 创建用户逻辑 ⭐
│   │   ├── getuserlogic.go     # 查询用户逻辑 ⭐
│   │   ├── updateuserlogic.go  # 更新用户逻辑 ⭐
│   │   └── deleteuserlogic.go  # 删除用户逻辑 ⭐
│   ├── model/
│   │   ├── usermodel.go        # Model 扩展(可编辑)
│   │   ├── usermodel_gen.go    # Model 基础(自动生成)
│   │   └── vars.go             # 错误定义
│   ├── svc/
│   │   └── servicecontext.go   # 服务上下文
│   └── types/
│       └── types.go            # 类型定义
├── sql/
│   └── user.sql                # 数据库建表语句
├── user.api                    # API 定义文件 ⭐
├── user.go                     # 入口文件
├── go.mod
└── go.sum

核心文件说明:

文件 作用 编辑建议
etc/user-api.yaml 配置文件 修改数据库连接等配置
internal/config/config.go 配置结构体 添加 MySQL 配置字段
user.api 定义 API 接口 根据需求编写,修改后重新生成代码
internal/logic/*.go 业务逻辑 重点编写,实现核心功能
internal/model/usermodel.go Model 扩展 可添加自定义查询方法
internal/model/usermodel_gen.go Model 基础 勿修改,重新生成会覆盖
internal/svc/servicecontext.go 服务上下文 注册 Model 依赖

六、总结

6.1 开发流程回顾

复制代码
创建项目 → 配置数据库 → 编写 API 文件 → 生成 API 代码 
    → 生成 Model → 注册服务上下文 → 编写逻辑 → 测试验证

6.2 关键命令速查

步骤 命令
创建项目 goctl api new mysqldemo
生成 API 代码 goctl api go -api user.api -dir .
生成 Model goctl model mysql ddl -src sql/user.sql -dir internal/model -c=false
启动服务 go run user.go -f etc/user-api.yaml
相关推荐
kebeiovo6 小时前
游戏服务端开发:Actor模型详解(Go语言)
开发语言·后端·golang
蓝田~7 小时前
MySQL慢查询怎么优化?B+Tree索引原理+MVCC读不阻塞写+EXPLAIN执行计划,从5秒到0.05秒
数据库·mysql
Herbert_hwt7 小时前
MySQL学习前言:关于MySQL的历史与当下学习的必要性
mysql
时间的拾荒人8 小时前
MySQL 视图详解
android·数据库·mysql
尽兴-9 小时前
企业数据库选型与演进:Oracle、达梦、MySQL 与分库分表实践
数据库·mysql·oracle·分库分表
Wang's Blog9 小时前
Go-Zero项目开发9: 微服务治理之服务注册中心
微服务·golang
IT瑞先生10 小时前
Docker快速部署Mysql的三种方法——实操篇
mysql·adb·docker
布朗克16810 小时前
Go 入门到精通-27-泛型编程
开发语言·golang·xcode·泛型编程
名字还没想好☜10 小时前
Go 用 errgroup 管理并发子任务:错误收敛、取消传播与限流
开发语言·后端·golang·go·并发
数据库小学妹10 小时前
MySQL在线DDL实战:ALGORITHM三种算法对比+gh-ost变更管理SOP
mysql·dba·数据库运维·在线ddl·mdl锁·sql变更管理