本篇文章采用go + gin +gorm +mysql 实现基本的数据库增删改查功能
1.首先第一步,我们需要安装框架。
在命令行中执行以下操作: 安装gin
go get -u github.com/gin-gonic/gin
安装gorm框架
go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
2.创建项目
创建main.go文件并使用init来初始化项目:
go mod init project
3.在main.go中引入依赖
import ("github.com/gin-gonic/gin"
"gorm.io/gorm"
"gorm.io/driver/sqlite")
4.连接数据库
dsn := "root:12345678@tcp(127.0.0.1:3306)/crud-demo?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
设置数据库的一些基本连接参数
sqlDB, err := db.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(10 * time.Second) // 10 秒钟
创建数据库的结构体
// 结构体
type List struct {
Name string
State string
Phone string
Email string
Address string
}
迁移 schema
db.AutoMigrate(&List{})
启动gin服务
r := gin.Default()
// 端口号
PORT := "3000"
r.Run(":" + PORT)
5.出现的小问题
如果按照上面那样设置,会出现两个小问题
5.1创建的表没有主键
解决办法:在创建结构体的时候添加gorm.model
GORM 定义了一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
所以现在List结构体变成了这样:
// 结构体
type List struct {
gorm.Model
Name string
State string
Phone string
Email string
Address string
}
2.创建的表会变成复数形式:lists
解决办法,在db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})的时候添加一段代码,现在的代码为:
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
// 解决查表的时候会自动添加复数的问题 , 例如 user 变成了 users
SingularTable: true,
},
})
6.完善结构体
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"`
}
注意点 :
- 结构体里面的变量 (Name) 必须是首字符大写
2.gorm 指定类型
3.json 表示json接受的时候的名称
4.binding:"required" 表示必须传入
接下来,可以按照restful编码规范编写增删改查接口了。
7.POST接口
主要就是首先定义一个List类型的变量data,将他绑定josn,之后分别编写添加成功和添加失败的逻辑,其中需要注意的是,添加成功以后还需要使用db.Create(&data) 来向数据库之中创建一条数据。
r.POST("/user/add", func(c *gin.Context) {
var data List
err := c.ShouldBindJSON(&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": data,
"code": 200,
})
}
})
8.DELETE接口
大致的思路如下:
- 找到对应的 id 所对应的条目
- 判断 id 是否存在
- 从数据库中删除
- 返回, id 不存在的情况下 代码如下:
r.DELETE("/user/delete/:id", func(c *gin.Context) {
var data []List
// 接受 id
id := c.Param("id")
// 判断 id 是否存在
db.Where("id = ?", id).Find(&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,
})
}
})
9.PUT接口的编写 即“改”的接口的编写
主要的思路如下:
- 找到对应的 id 所对应的条目
- 判断 id 是否存在
- 修改对应条目
- 返回 id,没有找到
代码如下:
r.PUT("/user/update/:id", func(c *gin.Context) {
var data List
// 接受 id
id := c.Param("id")
// 判断 id 是否存在
db.Select("id").Where("id = ? ", id).Find(&data)
// 判断 id 是否存在
if data.ID == 0 {
c.JSON(200, gin.H{
"msg": "用户id没有找到",
"code": 400,
})
} else {
err := c.ShouldBindJSON(&data)
if err != nil {
c.JSON(200, gin.H{
"msg": "修改失败",
"code": 400,
})
} else {
// db 修改数据库内容
db.Where("id = ?", id).Updates(&data)
c.JSON(200, gin.H{
"msg": "修改成功",
"code": 200,
})
}
}
})
10.GET接口的编写
10.1条件查询 按名称查询
其中需要注意的是var dataList []List,需要定义切片类型的变量来接受查询到的结果,因为有可能有名字相同的数据存在。
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,
})
}
})
11.查询全部数据 和分页处理数据
代码如下:
r.GET("/user/list", func(c *gin.Context) {
var dataList []List
// 1. 查询全部数据, 查询分页数据
pageSize, _ := strconv.Atoi(c.Query("pageSize"))
pageNum, _ := strconv.Atoi(c.Query("pageNum"))
// 判断是否需要分页
if pageSize == 0 {
pageSize = -1
}
if pageNum == 0 {
pageNum = -1
}
offsetVal := (pageNum - 1) * pageSize
if pageNum == -1 && pageSize == -1 {
offsetVal = -1
}
// 返回一个总数
var total int64
// 查询数据库
db.Model(dataList).Count(&total).Limit(pageSize).Offset(offsetVal).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": gin.H{
"list": dataList,
"total": total,
"pageNum": pageNum,
"pageSize": pageSize,
},
})
}
})
至此,crud全部完成,希望可以帮助到想要使用gorm完成crud功能的同学。
参考
GO + Gin + GORM + MySql 实现最基础的 CRUD 结尾+后续计划_哔哩哔哩_bilibili
GORM官方文档:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.