目录简介:开发环境:一、Gin0. 快速入门:1. 基准测试2. Gin的特性与JSONiter:二、GORM0. 特性与安装:三、Navicat连接数据库结构体定义与优化CRUD接
Q:Gin和Gorm都是干什么的?有什么区别?
A:Gin 和 Gorm 是 Go 编程语言中流行的开源库。但是,它们服务于不同的目的,通常在 WEB 开发项目中一起使用。
Gin 是一个用于构建 Http 服务器的 web 框架。它提供了一个简单易用的 api,用于处理 HTTP 请求和响应、路由、中间件和其他常见的 web 应用程序所需的功能。它以其高性能和简约为特点,提供了轻量级和灵活的解决方案来构建 web 服务器。
Gorm 是 Go 的一个 ORM(对象关系映射)库。它提供了一个简单易用的 API,用于与数据库交互、处理数据库迁移和执行常见的数据库操作,如查询、插入、更新和删除记录。它支持多种数据库后端,包括 Mysql、postgresql、sqlite 等。
总而言之, Gin 是用于处理 HTTP 请求和响应、路由、中间件和其他与网络相关的东西的 web 框架,而 Gorm 则是用于与数据库交互并执行常见数据库操作的 ORM 库。它们通常一起使用,来处理 HTTP 请求/响应并在 web 开发项目中存储或获取数据。
package main
import (
"encoding/json"
"net/http"
"GitHub.com/gin-gonic/gin"
"github.com/thinkerou/favicon"
)
// 中间件(拦截器),功能:预处理,登录授权、验证、分页、耗时统计...
// func myHandler() gin.HandlerFunc {
// return func(ctx *gin.Context) {
// // 通过自定义中间件,设置的值,在后续处理只要调用了这个中间件的都可以拿到这里的参数
// ctx.Set("usersesion", "userid-1")
// ctx.Next() // 放行
// ctx.Abort() // 阻止
// }
// }
func main() {
// 创建一个服务
ginServer := gin.Default()
ginServer.Use(favicon.New("./Arctime.ico")) // 这里如果添加了东西然后再运行没有变化,请重启浏览器,浏览器有缓存
// 加载静态页面
ginServer.LoadhtmlGlob("templates
// 看到后端的实时响应里面接收到数据就可以了
// 处理表单请求 这些都是支持函数式编程,Go语言特性,可以把函数作为参数传进来
ginServer.POST("/user/add", func(ctx *gin.Context) {
username := ctx.PostForm("username")
passWord := ctx.PostForm("password")
ctx.JSON(http.StatusOK, gin.H{
"msg": "ok",
"username": username,
"password": password,
})
})
// 路由
ginServer.GET("/test", func(ctx *gin.Context) {
// 重定向 -> 301
ctx.Redirect(301, "https://conqueror712.gitee.io/conqueror712.gitee.io/")
})
// http://localhost:8081/test
// 404
ginServer.NoRoute(func(ctx *gin.Context) {
ctx.HTML(404, "404.html", nil)
})
// 路由组暂略
// 服务器端口,用服务器端口来访问地址
ginServer.Run(":8081") // 不写的话默认是8080,也可以更改
}
API用法示例:https://gin-gonic.com/zh-cn/docs/examples/
Q:基准测试是什么?
A:基准测试,也称为性能测试或压力测试,是一种用于测量系统或组件性能的测试。基准测试的目的是了解系统或组件在特定条件下的性能,并将结果与其他类似系统或组件进行比较。基准测试可用于评估各种类型的系统和组件,包括硬件、软件、网络和整个系统。
Q:什么时候需要基准测试呀?
A:基准测试通常涉及在被测系统或组件上运行特定工作负载或任务,并测量吞吐量、延迟时间、CPU使用率、内存使用率等各种性能指标。基准测试的结果可用于识别瓶颈和性能问题,并做出有关如何优化系统或组件以提高性能的明智决策。
有许多不同类型的基准测试,每种类型都有自己的指标和工作负载。常见的基准测试类型包括:
重要的是要知道基准测试不是一次性的活动,而是应该定期进行的活动,以评估系统的性能并检测随时间的消耗。
Q:什么样的基准测试结果是我们想要的呀?
A:
Gin v1 稳定的特性:
Gin 使用 encoding/json 作为默认的 json 包,但是你可以在编译中使用标签将其修改为 jsoniter。
$ go build -tags=jsoniter .
Jsoniter是什么?
json-iterator
是一款快且灵活的JSON
解析器,同时提供Java
和Go
两个版本。json-iterator
是最快的JSON
解析器。它最多能比普通的解析器快10倍之多iterator api
能够直接遍历JSON
,极致性能、零内存分配下载依赖:go get github.com/json-iterator/go
Preload
、Joins
的预加载go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
其他的补充内容:
新建连接 -> mysql -> 连接名随便 -> 密码随便 -> 双击左侧打开 -> 右键information_schema -> 新建数据库 -> 名称crud-list -> 字符集utf8mb4
这里如果打开的时候报错navicat 1045 - access denied for user 'root'@'localhost' (using password: 'YES')
,则需要查看自己的数据库本身的问题
编写测试代码,成功运行即可,但是这个时候还不能查看数据库是否被创建,
如果要看我们需要定义结构体,然后定义表迁移,具体代码如下:
package main
import (
"fmt"
"time"
// "gorm.io/driver/sqlite"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
// 如何连接数据库 ? MySQL + Navicat
// 需要更改的内容:用户名,密码,数据库名称
dsn := "root:BqV?eGCc_1o+@tcp(127.0.0.1:3306)/crud-list?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
fmt.Println("db = ", db)
fmt.Println("err = ", err)
// 连接池
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
}
// 迁移
db.AutoMigrate(&List{})
// 接口
r := gin.Default()
// 端口号
PORT := "3001"
r.Run(":" + PORT)
}
定义好之后我们运行,没有报错并且在终端显示出来3001就是正确的,这个时候我们可以去Navicat里面查看crud-list下面的"表",刷新后发现有一个lists产生,那就是对的了。
但是这个时候我们存在两个问题:
gorm.Model
来解决,Ctrl+左键可以查看model
*db*, *err* *:=* gorm.Open(mysql.Open(dsn), *&*gorm.Config{})
里面添加一段话即可更改完成之后我们要先在Navicat里面把原来的表lists
删掉才能重新创建,这个时候我们重新运行,就会发现表单里面多了很多东西
例如:
`gorm:"type:varchar(20); not null" json:"name" binding:"required"`
需要注意的是:
// 测试
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "请求成功",
})
})
编写完这一段之后运行代码,然后去postman里面新建一个GET接口127.0.0.1:3001
然后send一下,出现请求成功就请求成功了。
增也是一样,写好之后直接用如下JSON来测试就可以:
{
"name" : "张三",
"state" : "在职",
"phone" : "13900000000",
"email" : "6666@qq.com",
"address" : "二仙桥成华大道"
}
返回:
{
"code": "200",
"data": {
"ID": 1,
"CreatedAt": "2023-01-24T09:27:36.73+08:00",
"UpdatedAt": "2023-01-24T09:27:36.73+08:00",
"DeletedAt": null,
"name": "张三",
"state": "在职",
"phone": "13900000000",
"email": "6666@qq.com",
"address": "二仙桥成华大道"
},
"msg": "添加成功"
}
这时候也可以在数据库里看到这条数据
删除也是一样,编写完运行之后添加一个DELETE接口,然后输入127.0.0.1:3001/user/delete/2
之后send就可以看到返回了(前提是有数据)
{
"code": 200,
"msg": "删除成功"
}
如果是删除了不存在的id,就会返回
{
"code": 400,
"msg": "id没有找到,删除失败"
}
顺带一提,事实上这个代码还可以优化,这里的if else太多了,后面优化的时候有错误直接return
修改也是一样,示例:
{
"name" : "张三",
"state" : "离职",
"phone" : "13900000000",
"email" : "6666@qq.com",
"address" : "二仙桥成华大道"
}
返回:
{
"code": 200,
"msg": "修改成功"
}
查询分为两种:
条件查询的话,直接写好了请求127.0.0.1:3001/user/list/王五
返回:
{
"code": "200",
"data": [
{
"ID": 3,
"CreatedAt": "2023-01-24T10:06:25.305+08:00",
"UpdatedAt": "2023-01-24T10:06:25.305+08:00",
"DeletedAt": null,
"name": "王五",
"state": "在职",
"phone": "13100000000",
"email": "8888@qq.com",
"address": "八仙桥成华大道"
}
],
"msg": "查询成功"
}
全部 / 分页查询的话
譬如说请求是:127.0.0.1:3001/user/list?pageNum=1&pageSize=2
意思就是查询第一页的两个
返回:
{
"code": 200,
"data": {
"list": [
{
"ID": 3,
"CreatedAt": "2023-01-24T10:06:25.305+08:00",
"UpdatedAt": "2023-01-24T10:06:25.305+08:00",
"DeletedAt": null,
"name": "王五",
"state": "在职",
"phone": "13100000000",
"email": "8888@qq.com",
"address": "八仙桥成华大道"
}
],
"pageNum": 1,
"pageSize": 2,
"total": 2
},
"msg": "查询成功"
}
如果请求是:127.0.0.1:3001/user/list
返回:
{
"code": 200,
"data": {
"list": [
{
"ID": 1,
"CreatedAt": "2023-01-24T09:27:36.73+08:00",
"UpdatedAt": "2023-01-24T09:55:20.351+08:00",
"DeletedAt": null,
"name": "张三",
"state": "离职",
"phone": "13900000000",
"email": "6666@qq.com",
"address": "二仙桥成华大道"
},
{
"ID": 3,
"CreatedAt": "2023-01-24T10:06:25.305+08:00",
"UpdatedAt": "2023-01-24T10:06:25.305+08:00",
"DeletedAt": null,
"name": "王五",
"state": "在职",
"phone": "13100000000",
"email": "8888@qq.com",
"address": "八仙桥成华大道"
}
],
"pageNum": 0,
"pageSize": 0,
"total": 2
},
"msg": "查询成功"
}
完整代码如下:
package main
import (
"fmt"
"strconv"
"time"
// "gorm.io/driver/sqlite"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
func main() {
// 如何连接数据库 ? MySQL + Navicat
// 需要更改的内容:用户名,密码,数据库名称
dsn := "root:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
fmt.Println("db = ", db)
fmt.Println("err = ", err)
// 连接池
sqlDB, err := db.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(10 * time.Second) // 10秒钟
// 结构体
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"`
}
// 迁移
db.AutoMigrate(&List{})
// 接口
r := gin.Default()
// 测试
// r.GET("/", func(c *gin.Context) {
// c.JSON(200, gin.H{
// "message": "请求成功",
// })
// })
// 业务码约定:正确200,错误400
// 增
r.POST("/user/add", func(ctx *gin.Context) {
// 定义一个变量指向结构体
var data List
// 绑定方法
err := ctx.ShouldBindJSON(&data)
// 判断绑定是否有错误
if err != nil {
ctx.JSON(200, gin.H{
"msg": "添加失败",
"data": gin.H{},
"code": "400",
})
} else {
// 数据库的操作
db.Create(&data) // 创建一条数据
ctx.JSON(200, gin.H{
"msg": "添加成功",
"data": data,
"code": "200",
})
}
})
// 删
// 1. 找到对应的id对应的条目
// 2. 判断id是否存在
// 3. 从数据库中删除 or 返回id没有找到
// Restful编码规范
r.DELETE("/user/delete/:id", func(ctx *gin.Context) {
var data []List
// 接收id
id := ctx.Param("id") // 如果有键值对形式的话用Query()
// 判断id是否存在
db.Where("id = ? ", id).Find(&data)
if len(data) == 0 {
ctx.JSON(200, gin.H{
"msg": "id没有找到,删除失败",
"code": 400,
})
} else {
// 操作数据库删除(删除id所对应的那一条)
// db.Where("id = ? ", id).Delete(&data) <- 其实不需要这样写,因为查到的data里面就是要删除的数据
db.Delete(&data)
ctx.JSON(200, gin.H{
"msg": "删除成功",
"code": 200,
})
}
})
// 改
r.PUT("/user/update/:id", func(ctx *gin.Context) {
// 1. 找到对应的id所对应的条目
// 2. 判断id是否存在
// 3. 修改对应条目 or 返回id没有找到
var data List
id := ctx.Param("id")
// db.Where("id = ?", id).Find(&data) 可以这样写,也可以写成下面那样
// 还可以再Where后面加上Count函数,可以查出来这个条件对应的条数
db.Select("id").Where("id = ? ", id).Find(&data)
if data.ID == 0 {
ctx.JSON(200, gin.H{
"msg": "用户id没有找到",
"code": 400,
})
} else {
// 绑定一下
err := ctx.ShouldBindJSON(&data)
if err != nil {
ctx.JSON(200, gin.H{
"msg": "修改失败",
"code": 400,
})
} else {
// db修改数据库内容
db.Where("id = ?", id).Updates(&data)
ctx.JSON(200, gin.H{
"msg": "修改成功",
"code": 200,
})
}
}
})
// 查
// 第一种:条件查询,
r.GET("/user/list/:name", func(ctx *gin.Context) {
// 获取路径参数
name := ctx.Param("name")
var dataList []List
// 查询数据库
db.Where("name = ? ", name).Find(&dataList)
// 判断是否查询到数据
if len(dataList) == 0 {
ctx.JSON(200, gin.H{
"msg": "没有查询到数据",
"code": "400",
"data": gin.H{},
})
} else {
ctx.JSON(200, gin.H{
"msg": "查询成功",
"code": "200",
"data": dataList,
})
}
})
// 第二种:全部查询 / 分页查询
r.GET("/user/list", func(ctx *gin.Context) {
var dataList []List
// 查询全部数据 or 查询分页数据
pageSize, _ := strconv.Atoi(ctx.Query("pageSize"))
pageNum, _ := strconv.Atoi(ctx.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 {
ctx.JSON(200, gin.H{
"msg": "没有查询到数据",
"code": 400,
"data": gin.H{},
})
} else {
ctx.JSON(200, gin.H{
"msg": "查询成功",
"code": 200,
"data": gin.H{
"list": dataList,
"total": total,
"pageNum": pageNum,
"pageSize": pageSize,
},
})
}
})
// 端口号
PORT := "3001"
r.Run(":" + PORT)
}
到此这篇关于Gin+Gorm实战CRUD的文章就介绍到这了,更多相关Gin Gorm CRUD内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: Gin+Gorm实现CRUD的实战
本文链接: https://lsjlt.com/news/194058.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-04-05
2024-04-05
2024-04-05
2024-04-04
2024-04-05
2024-04-05
2024-04-05
2024-04-05
2024-04-04
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0