GO + Gin + GORM + MySql 实现最基础的 CRUD | 青训营

539 阅读8分钟

GO + Gin + GORM + MySql 实现最基础的 CRUD

什么是CRUD? CRUD的操作

CRUD是指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。主要被用在描述软件系统中DataBase或者持久层的基本操作功能。

视频网址:GO + Gin + GORM + MySql 实现最基础的 CRUD get请求全部数据和分页数据哔哩哔哩bilibili

准备工具

1.安装 go 的环境 www.runoob.com/go/go-envir…

2.安装数据库mysql

3.安装一个测试工具,postman/apipost(apipost是中文,推荐) Apipost-API 文档、设计、调试、自动化测试一体化协作平台

  1. golang /vscode

  2. gin和grom的中文文档

    www.kancloud.cn/shuangdeyu/…

    gorm.io/zh_CN/docs/

  3. navicat 数据库的查询

功能介绍

使用测试工具发起请求

通过post请求127.0.0.1:3001/user/add 可以增加数据

通过delete请求127.0.0.1:3001/user/delete/id(这里填参数) 软删除数据

通过put请求127.0.0.1:3001/user/update/id(这里填参数) 更新数据

通过get请求127.0.0.1:3001/user/List 获取所有数据

通过get请求127.0.0.1:3001/user/List 传入pageSize query查询和 pageNUM query参数进行分页查询

搭建服务端口

package main
​
import (
    "fmt"
    "strconv"
    "time""github.com/gin-gonic/gin" //加入gin
    "gorm.io/driver/mysql" //加入mysql
    "gorm.io/gorm"      //加入grom
    "gorm.io/gorm/schema" //加入grom
    //    "gorm.io/driver/sqlite"
)
​
func main() {
    //连接到数据库,用户名为root,密码为空,连接到的数据库名是curd-list
    dsn := "root:@tcp(127.0.0.1:3306)/curd-list?charset=utf8mb4&parseTime=True&loc=Local" //一般数据库的连接都是127.0.0.1:3306,不用改
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
        NamingStrategy: schema.NamingStrategy{
            SingularTable: true, // 使用单数表名,启用此选项后,“User”的表将为“Users”
        },
    })
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(db)
​
    sqlDB, err := db.DB()
​
    // SetMaxIdleConns设置空闲连接池中的最大连接数。
    sqlDB.SetMaxIdleConns(10)
​
    //SetMaxOpenConns设置数据库的最大打开连接数。
    sqlDB.SetMaxOpenConns(100)
​
    // SetConnMaxLifetime设置连接可以重复使用的最长时间。
    sqlDB.SetConnMaxLifetime(10 * time.Second) //十秒钟//定义表结构体
    type List struct {
        gorm.Model        //每次都要添加到结构体
        Name       string `gorm:"type:varchar(20); not null" json:"name" binding:"required"`
        State      string `gorm:"type:varchar(20); not null" json:"state" binding:"required"`
        Phone      string `gorm:"type:varchar(20); not null" json:"phone" binding:"required"`
        Email      string `gorm:"type:varchar(40); not null" json:"email" binding:"required"`
        Address    string `gorm:"type:varchar(200); not null" json:"address" binding:"required"` //binding:"required"是指这行数据必须填写
    }
​
    //1.主键没有    结构体添加gorm.Model
    //2.名称变成复数问题
    //AutoMigrate 会创建表、缺失的外键、约束、列和索引
    db.AutoMigrate(&List{}) //创建表//创建接口
    r := gin.Default()
​
    /*代码约定
​
    成功:200
    错误:400
​
    *///测试
    r.GET("/", func(c *gin.Context) { //发起get请求,执行的函数操作
        c.JSON(200, gin.H{
            "message": "pong", //返回的json请求
        })
    })
        //客户端的访问端口号  
    PORT := "3001"   //127.0.0.1:3001
    r.Run(":" + PORT) //运行端口 127.0.0.1:3001
}              

POST增加接口

    r.POST("/user/add", func(c *gin.Context) { //post请求访问127.0.0.1:3001/user/add
        var data List                  //创建List结构体对象
        err := c.ShouldBindJSON(&data) //ShouldBindJSON是gin框架提供的一个方法,用于将请求的JSON数据解析成结构体或map(传进data),并将解析结果绑定到指定的变量上。//判断是否成功
        if err != nil {
            c.JSON(200, gin.H{
                "msg":  "添加失败",
                "data": gin.H{},
                "code": 400,
            })
        } else {
            //请求成功后进行数据库操作
            db.Create(&data) //在数据库中创建一条接收到的数据
            c.JSON(200, gin.H{
                "msg":  "添加成功",
                "data": gin.H{},
                "code": 200,
            })
        }
    })

delete删除接口

//删
    //1.找到对应的id所对应的条目
    //2.判断id是否存在
    //3.从数据库中删除
    //4.返回,id没有找到//restful 编码风格 风格//一般用 get和post ,实际上post和delete是一样的
​
    r.DELETE("/user/delete/:id", func(c *gin.Context) {
        //nam=name,:id,这样填,nam,id都是接收到的参数
        var data []List //创建表
        //接受 id
        id := c.Param("id")
        //判断 id是否存在
        db.Where("id= ?", id).Find(&data) //where为判断条件语句,如果存在,将参数传入data//id存在的情况,则删除,不存在则保存
        if len(data) == 0 {
            c.JSON(200, gin.H{
                "msg":  "id没有找到,删除失败",
                "code": 400,
            })
​
        } else {
            //操作数据库删除
            db.Where("id = ?", id).Delete(&data)
            c.JSON(200, gin.H{
                "msg":  "删除成功",
                "code": 200,
            })
        }
    })

put修改接口

//改
    //1.找到对应的id所对应的条目
    //2.判断id是否存在
    //3.更改条目
    //4.返回,id没有找到
    r.PUT("/user/update/:id", func(c *gin.Context) {
        var data List
        id := c.Param("id")                             //将参数传入id
        db.Select("id").Where("id = ?", id).Find(&data) //将找到的那一行id数据传入data
        if data.ID == 0 {                               //判断id是否存在
            c.JSON(200, gin.H{
                "msg":  "id不存在",
                "code": 400,
            })
        } else {
            err := c.ShouldBindJSON(&data) //将接收到的json参数传进data
            if err != nil {
                c.JSON(200, gin.H{
                    "msg":  "更新失败",
                    "code": 400,
                })
            } else {
                db.Where("id = ?", id).Updates(&data)
                c.JSON(200, gin.H{
                    "msg":  "更新成功",
                    "code": 200,
                })
            }
        }
    })
​

get请求全部数据和分页数据

//查 (条件查询,全部查询 / 分页查询)// 条件查询
    r.GET("/user/List/:name", func(c *gin.Context) {
        //获取路径参数
        name := c.Param("name")
​
        var dataList []List
​
        //查询数据库
        db.Where("name = ?", name).Find(&dataList)
​
        //判断是否查询到数据if len(dataList) == 0 {
            c.JSON(200, gin.H{
                "msg":  "找不到对应数据",
                "code": 400,
                "data": gin.H{},
            })
        } else {
            c.JSON(200, gin.H{
                "msg":  "找到对应数据",
                "code": 200,
                "data": dataList,
            })
        }
​
    })
    //全部查询
    r.GET("user/List", func(c *gin.Context) {
        var dataList []List
        var total int64 //总数据条数//查询全部数据,查询分页数据
        pageSize, _ := strconv.Atoi(c.Query("pageSize")) //Query意思是当json查询传入pageSize参数数据时候,返回的变量给pageSize
        pageNUM, _ := strconv.Atoi(c.Query("pageNUM"))   //int,_ = strconv.Atoi(string) 将string转成int类型
        //pageNUM 请求几条数据
        //Limit 限制页面大小,数据条数  Offset 翻页,第几页
        offsetVal := (pageNUM - 1) * pageSize //offsetVal 偏移值
        if pageSize == -1 && pageNUM == -1 {
            offsetVal = -1
        }
        //如果不需要翻页
        if pageSize == 0 {
            pageSize = -1
        }
        if pageNUM == 0 {
            pageNUM = -1
        }
        //查询数据
        db.Model(dataList).Count(&total).Limit(pageSize).Offset(offsetVal).Find(&dataList) //Limit(-1).Offset(-1)指的是查询所有数据,Model(dataList).Count(&total),Count记录数据条数,最后将数据传入dataList
        if len(dataList) == 0 {
            c.JSON(200, gin.H{
                "msg":  "没有查询到数据",
                "code": 400,
            })
        } else {
            c.JSON(200, gin.H{
                "msg":      "查询到数据",
                "code":     200,
                "data":     dataList,
                "total":    total,
                "pageSize": pageSize,
                "pageNUM":  pageNUM,
            })
        }
    })

完整代码

package main
​
import (
    "fmt"
    "strconv"
    "time""github.com/gin-gonic/gin"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
    //    "gorm.io/driver/sqlite"
)
​
func main() {
    //连接到数据库,用户名为root,密码为空,连接到的数据库名是curd-list
    dsn := "root:@tcp(127.0.0.1:3306)/curd-list?charset=utf8mb4&parseTime=True&loc=Local" //一般数据库的连接都是127.0.0.1:3306,不用改
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
        NamingStrategy: schema.NamingStrategy{
            SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
        },
    })
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(db)
​
    sqlDB, err := db.DB()
​
    // SetMaxIdleConns设置空闲连接池中的最大连接数。
    sqlDB.SetMaxIdleConns(10)
​
    //SetMaxOpenConns设置数据库的最大打开连接数。
    sqlDB.SetMaxOpenConns(100)
​
    // SetConnMaxLifetime设置连接可以重复使用的最长时间。
    sqlDB.SetConnMaxLifetime(10 * time.Second) //十秒钟//结构体
    type List struct {
        gorm.Model        //每次都要添加到结构体
        Name       string `gorm:"type:varchar(20); not null" json:"name" binding:"required"`
        State      string `gorm:"type:varchar(20); not null" json:"state" binding:"required"`
        Phone      string `gorm:"type:varchar(20); not null" json:"phone" binding:"required"`
        Email      string `gorm:"type:varchar(40); not null" json:"email" binding:"required"`
        Address    string `gorm:"type:varchar(200); not null" json:"address" binding:"required"` //binding:"required"是指这行数据必须填写
    }
​
    //1.主键没有    结构体添加gorm.Model
    //2.名称变成复数问题
    //AutoMigrate 会创建表、缺失的外键、约束、列和索引
    db.AutoMigrate(&List{}) //创建表//接口
    r := gin.Default()
​
    /*代码约定
​
    成功:200
    错误:400
​
    *///测试
    r.GET("/", func(c *gin.Context) { //发起get请求,执行的函数操作
        c.JSON(200, gin.H{
            "message": "pong", //返回的json请求
        })
    })
​
    //增
​
    r.POST("/user/add", func(c *gin.Context) {
        var data List                  //创建List结构体对象
        err := c.ShouldBindJSON(&data) //ShouldBindJSON是gin框架提供的一个方法,用于将请求的JSON数据解析成结构体或map(传进data),并将解析结果绑定到指定的变量上。//判断是否成功
        if err != nil {
            c.JSON(200, gin.H{
                "msg":  "添加失败",
                "data": gin.H{},
                "code": 400,
            })
        } else {
            //请求成功后进行数据库操作
            db.Create(&data) //在数据库中创建一条接收到的数据
            c.JSON(200, gin.H{
                "msg":  "添加成功",
                "data": gin.H{},
                "code": 200,
            })
        }
    })
    /*{
        "name":"张三",
        "state":"在职",
        "phone":"2445678",
        "email":"234367@qq.com",
        "address":"东莞",
    }
    //测试用的json
    *///删
    //1.找到对应的id所对应的条目
    //2.判断id是否存在
    //3.从数据库中删除
    //4.返回,id没有找到//restful 编码风格 风格//一般用 get和post ,实际上post和delete是一样的
​
    r.DELETE("/user/delete/:id", func(c *gin.Context) {
        //nam=name,:id,这样填,nam,id都是接收到的参数
        var data []List //创建表
        //接受 id
        id := c.Param("id")
        //判断 id是否存在
        db.Where("id= ?", id).Find(&data) //where为判断条件语句,如果存在,将参数传入data//id存在的情况,则删除,不存在则保存
        if len(data) == 0 {
            c.JSON(200, gin.H{
                "msg":  "id没有找到,删除失败",
                "code": 400,
            })
​
        } else {
            //操作数据库删除
            db.Where("id = ?", id).Delete(&data)
            c.JSON(200, gin.H{
                "msg":  "删除成功",
                "code": 200,
            })
        }
    })
    //
    //改
    //1.找到对应的id所对应的条目
    //2.判断id是否存在
    //3.更改条目
    //4.返回,id没有找到
    r.PUT("/user/update/:id", func(c *gin.Context) {
        var data List
        id := c.Param("id")                             //将参数传入id
        db.Select("id").Where("id = ?", id).Find(&data) //将找到的那一行id数据传入data
        if data.ID == 0 {                               //判断id是否存在
            c.JSON(200, gin.H{
                "msg":  "id不存在",
                "code": 400,
            })
        } else {
            err := c.ShouldBindJSON(&data) //将接收到的json参数传进data
            if err != nil {
                c.JSON(200, gin.H{
                    "msg":  "更新失败",
                    "code": 400,
                })
            } else {
                db.Where("id = ?", id).Updates(&data)
                c.JSON(200, gin.H{
                    "msg":  "更新成功",
                    "code": 200,
                })
            }
        }
    })
​
    //查 (条件查询,全部查询 / 分页查询)// 条件查询
    r.GET("/user/List/:name", func(c *gin.Context) {
        //获取路径参数
        name := c.Param("name")
​
        var dataList []List
​
        //查询数据库
        db.Where("name = ?", name).Find(&dataList)
​
        //判断是否查询到数据if len(dataList) == 0 {
            c.JSON(200, gin.H{
                "msg":  "找不到对应数据",
                "code": 400,
                "data": gin.H{},
            })
        } else {
            c.JSON(200, gin.H{
                "msg":  "找到对应数据",
                "code": 200,
                "data": dataList,
            })
        }
​
    })
    //全部查询
    r.GET("user/List", func(c *gin.Context) {
        var dataList []List
        var total int64 //总数据条数//查询全部数据,查询分页数据
        pageSize, _ := strconv.Atoi(c.Query("pageSize")) //Query意思是当json查询传入pageSize参数数据时候,返回的变量给pageSize
        pageNUM, _ := strconv.Atoi(c.Query("pageNUM"))   //int,_ = strconv.Atoi(string) 将string转成int类型
        //pageNUM 请求几条数据
        //Limit 限制页面大小,数据条数  Offset 翻页,第几页
        offsetVal := (pageNUM - 1) * pageSize //offsetVal 偏移值
        if pageSize == -1 && pageNUM == -1 {
            offsetVal = -1
        }
        //如果不需要翻页
        if pageSize == 0 {
            pageSize = -1
        }
        if pageNUM == 0 {
            pageNUM = -1
        }
        //查询数据
        db.Model(dataList).Count(&total).Limit(pageSize).Offset(offsetVal).Find(&dataList) //Limit(-1).Offset(-1)指的是查询所有数据,Model(dataList).Count(&total),Count记录数据条数,最后将数据传入dataList
        if len(dataList) == 0 {
            c.JSON(200, gin.H{
                "msg":  "没有查询到数据",
                "code": 400,
            })
        } else {
            c.JSON(200, gin.H{
                "msg":      "查询到数据",
                "code":     200,
                "data":     dataList,
                "total":    total,
                "pageSize": pageSize,
                "pageNUM":  pageNUM,
            })
        }
    })
​
    //访问端口号
    PORT := "3002"
    r.Run(":" + PORT)
}
​