Gin+Gorm實(shí)現(xiàn)CRUD的實(shí)戰(zhàn)
簡(jiǎn)介:
Q:Gin和Gorm都是干什么的?有什么區(qū)別?
A:Gin 和 Gorm 是 Go 編程語(yǔ)言中流行的開(kāi)源庫(kù)。但是,它們服務(wù)于不同的目的,通常在 web 開(kāi)發(fā)項(xiàng)目中一起使用。
Gin 是一個(gè)用于構(gòu)建 HTTP 服務(wù)器的 web 框架。它提供了一個(gè)簡(jiǎn)單易用的 API,用于處理 HTTP 請(qǐng)求和響應(yīng)、路由、中間件和其他常見(jiàn)的 web 應(yīng)用程序所需的功能。它以其高性能和簡(jiǎn)約為特點(diǎn),提供了輕量級(jí)和靈活的解決方案來(lái)構(gòu)建 web 服務(wù)器。
Gorm 是 Go 的一個(gè) ORM(對(duì)象關(guān)系映射)庫(kù)。它提供了一個(gè)簡(jiǎn)單易用的 API,用于與數(shù)據(jù)庫(kù)交互、處理數(shù)據(jù)庫(kù)遷移和執(zhí)行常見(jiàn)的數(shù)據(jù)庫(kù)操作,如查詢、插入、更新和刪除記錄。它支持多種數(shù)據(jù)庫(kù)后端,包括 MySQL、PostgreSQL、SQLite 等。
總而言之, Gin 是用于處理 HTTP 請(qǐng)求和響應(yīng)、路由、中間件和其他與網(wǎng)絡(luò)相關(guān)的東西的 web 框架,而 Gorm 則是用于與數(shù)據(jù)庫(kù)交互并執(zhí)行常見(jiàn)數(shù)據(jù)庫(kù)操作的 ORM 庫(kù)。它們通常一起使用,來(lái)處理 HTTP 請(qǐng)求/響應(yīng)并在 web 開(kāi)發(fā)項(xiàng)目中存儲(chǔ)或獲取數(shù)據(jù)。
開(kāi)發(fā)環(huán)境:
- Windows 10
- VSCode
一、Gin
0. 快速入門(mén):
package main
import (
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
"github.com/thinkerou/favicon"
)
// 中間件(攔截器),功能:預(yù)處理,登錄授權(quán)、驗(yàn)證、分頁(yè)、耗時(shí)統(tǒng)計(jì)...
// func myHandler() gin.HandlerFunc {
// return func(ctx *gin.Context) {
// // 通過(guò)自定義中間件,設(shè)置的值,在后續(xù)處理只要調(diào)用了這個(gè)中間件的都可以拿到這里的參數(shù)
// ctx.Set("usersesion", "userid-1")
// ctx.Next() // 放行
// ctx.Abort() // 阻止
// }
// }
func main() {
// 創(chuàng)建一個(gè)服務(wù)
ginServer := gin.Default()
ginServer.Use(favicon.New("./Arctime.ico")) // 這里如果添加了東西然后再運(yùn)行沒(méi)有變化,請(qǐng)重啟瀏覽器,瀏覽器有緩存
// 加載靜態(tài)頁(yè)面
ginServer.LoadHTMLGlob("templates/*") // 一種是全局加載,一種是加載指定的文件
// 加載資源文件
ginServer.Static("/static", "./static")
// 相應(yīng)一個(gè)頁(yè)面給前端
ginServer.GET("/index", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.html", gin.H{
"msg": "This data is come from Go background.",
})
})
// 能加載靜態(tài)頁(yè)面也可以加載測(cè)試文件
// 獲取請(qǐng)求中的參數(shù)
// 傳統(tǒng)方式:usl?userid=xxx&username=conqueror712
// Rustful方式:/user/info/1/conqueror712
// 下面是傳統(tǒng)方式的例子
ginServer.GET("/user/info", func(context *gin.Context) { // 這個(gè)格式是固定的
userid := context.Query("userid")
username := context.Query("username")
// 拿到之后返回給前端
context.JSON(http.StatusOK, gin.H{
"userid": userid,
"username": username,
})
})
// 此時(shí)執(zhí)行代碼之后,在瀏覽器中可以輸入http://localhost:8081/user/info?userid=111&username=666
// 就可以看到返回了JSON格式的數(shù)據(jù)
// 下面是Rustful方式的例子
ginServer.GET("/user/info/:userid/:username", func(context *gin.Context) {
userid := context.Param("userid")
username := context.Param("username")
// 還是一樣,返回給前端
context.JSON(http.StatusOK, gin.H{
"userid": userid,
"username": username,
})
})
// 指定代碼后,只需要在瀏覽器中http://localhost:8081/user/info/111/555
// 就可以看到返回了JSON數(shù)據(jù)了,非常方便簡(jiǎn)潔
// 序列化
// 前端給后端傳遞JSON
ginServer.POST("/json", func(ctx *gin.Context) {
// request.body
data, _ := ctx.GetRawData()
var m map[string]interface{} // Go語(yǔ)言中object一般用空接口來(lái)表示,可以接收anything
// 順帶一提,1.18以上,interface可以直接改成any
_ = json.Unmarshal(data, &m)
ctx.JSON(http.StatusOK, m)
})
// 用apipost或者postman寫(xiě)一段json傳到localhost:8081/json里就可以了
/*
json示例:
{
"name": "Conqueror712",
"age": 666,
"address": "Mars"
}
*/
// 看到后端的實(shí)時(shí)響應(yīng)里面接收到數(shù)據(jù)就可以了
// 處理表單請(qǐng)求 這些都是支持函數(shù)式編程,Go語(yǔ)言特性,可以把函數(shù)作為參數(shù)傳進(jìn)來(lái)
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)
})
// 路由組暫略
// 服務(wù)器端口,用服務(wù)器端口來(lái)訪問(wèn)地址
ginServer.Run(":8081") // 不寫(xiě)的話默認(rèn)是8080,也可以更改
}
API用法示例:https://gin-gonic.com/zh-cn/docs/examples/
1. 基準(zhǔn)測(cè)試
Q:基準(zhǔn)測(cè)試是什么?
A:基準(zhǔn)測(cè)試,也稱為性能測(cè)試或壓力測(cè)試,是一種用于測(cè)量系統(tǒng)或組件性能的測(cè)試?;鶞?zhǔn)測(cè)試的目的是了解系統(tǒng)或組件在特定條件下的性能,并將結(jié)果與其他類(lèi)似系統(tǒng)或組件進(jìn)行比較?;鶞?zhǔn)測(cè)試可用于評(píng)估各種類(lèi)型的系統(tǒng)和組件,包括硬件、軟件、網(wǎng)絡(luò)和整個(gè)系統(tǒng)。
Q:什么時(shí)候需要基準(zhǔn)測(cè)試呀?
A:基準(zhǔn)測(cè)試通常涉及在被測(cè)系統(tǒng)或組件上運(yùn)行特定工作負(fù)載或任務(wù),并測(cè)量吞吐量、延遲時(shí)間、CPU使用率、內(nèi)存使用率等各種性能指標(biāo)?;鶞?zhǔn)測(cè)試的結(jié)果可用于識(shí)別瓶頸和性能問(wèn)題,并做出有關(guān)如何優(yōu)化系統(tǒng)或組件以提高性能的明智決策。
有許多不同類(lèi)型的基準(zhǔn)測(cè)試,每種類(lèi)型都有自己的指標(biāo)和工作負(fù)載。常見(jiàn)的基準(zhǔn)測(cè)試類(lèi)型包括:
- 人工基準(zhǔn)測(cè)試:使用人工工作負(fù)載來(lái)測(cè)量系統(tǒng)或組件的性能。
- 真實(shí)世界基準(zhǔn)測(cè)試:使用真實(shí)世界的工作負(fù)載或場(chǎng)景來(lái)測(cè)量系統(tǒng)或組件的性能。
- 壓力測(cè)試:旨在將系統(tǒng)或組件推到極限,以確定在正常使用條件下可能不明顯的性能問(wèn)題
重要的是要知道基準(zhǔn)測(cè)試不是一次性的活動(dòng),而是應(yīng)該定期進(jìn)行的活動(dòng),以評(píng)估系統(tǒng)的性能并檢測(cè)隨時(shí)間的消耗。
Q:什么樣的基準(zhǔn)測(cè)試結(jié)果是我們想要的呀?
A:
- 在一定的時(shí)間內(nèi)實(shí)現(xiàn)的總調(diào)用數(shù),越高越好
- 單次操作耗時(shí)(ns/op),越低越好
- 堆內(nèi)存分配 (B/op), 越低越好
- 每次操作的平均內(nèi)存分配次數(shù)(allocs/op),越低越好
2. Gin的特性與Jsoniter:
Gin v1 穩(wěn)定的特性:
- 零分配路由。
- 仍然是最快的 http 路由器和框架。
- 完整的單元測(cè)試支持。
- 實(shí)戰(zhàn)考驗(yàn)。
- API 凍結(jié),新版本的發(fā)布不會(huì)破壞你的代碼。
- Gin 項(xiàng)目可以輕松部署在任何云提供商上。
Gin 使用 encoding/json 作為默認(rèn)的 json 包,但是你可以在編譯中使用標(biāo)簽將其修改為 jsoniter。
$ go build -tags=jsoniter .
Jsoniter是什么?
json-iterator是一款快且靈活的JSON解析器,同時(shí)提供Java和Go兩個(gè)版本。json-iterator是最快的JSON解析器。它最多能比普通的解析器快10倍之多- 獨(dú)特的
iterator api能夠直接遍歷JSON,極致性能、零內(nèi)存分配 - 從dsljson和jsonparser借鑒了大量代碼。
下載依賴:go get github.com/json-iterator/go
二、GORM
0. 特性與安裝:
- 全功能 ORM
- 關(guān)聯(lián) (Has One,Has Many,Belongs To,Many To Many,多態(tài),單表繼承)
- Create,Save,Update,Delete,F(xiàn)ind 中鉤子方法
- 支持
Preload、Joins的預(yù)加載 - 事務(wù),嵌套事務(wù),Save Point,Rollback To Saved Point
- Context、預(yù)編譯模式、DryRun 模式
- 批量插入,F(xiàn)indInBatches,F(xiàn)ind/Create with Map,使用 SQL 表達(dá)式、Context Valuer 進(jìn)行 CRUD
- SQL 構(gòu)建器,Upsert,數(shù)據(jù)庫(kù)鎖,Optimizer/Index/Comment Hint,命名參數(shù),子查詢
- 復(fù)合主鍵,索引,約束
- Auto Migration
- 自定義 Logger
- 靈活的可擴(kuò)展插件 API:Database Resolver(多數(shù)據(jù)庫(kù),讀寫(xiě)分離)、Prometheus…
- 每個(gè)特性都經(jīng)過(guò)了測(cè)試的重重考驗(yàn)
- 開(kāi)發(fā)者友好
go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
其他的補(bǔ)充內(nèi)容:
- Gorm是軟刪除,為了保證數(shù)據(jù)庫(kù)的完整性
三、Navicat
新建連接 -> MySQL -> 連接名隨便 -> 密碼隨便 -> 雙擊左側(cè)打開(kāi) -> 右鍵information_schema -> 新建數(shù)據(jù)庫(kù) -> 名稱crud-list -> 字符集utf8mb4
這里如果打開(kāi)的時(shí)候報(bào)錯(cuò)navicat 1045 - access denied for user 'root'@'localhost' (using password: 'YES'),則需要查看自己的數(shù)據(jù)庫(kù)本身的問(wèn)題
四、Gin+Gorm的CRUD
連接數(shù)據(jù)庫(kù)
編寫(xiě)測(cè)試代碼,成功運(yùn)行即可,但是這個(gè)時(shí)候還不能查看數(shù)據(jù)庫(kù)是否被創(chuàng)建,
如果要看我們需要定義結(jié)構(gòu)體,然后定義表遷移,具體代碼如下:
package main
import (
"fmt"
"time"
// "gorm.io/driver/sqlite"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
// 如何連接數(shù)據(jù)庫(kù) ? MySQL + Navicat
// 需要更改的內(nèi)容:用戶名,密碼,數(shù)據(jù)庫(kù)名稱
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 設(shè)置空閑連接池中連接的最大數(shù)量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 設(shè)置打開(kāi)數(shù)據(jù)庫(kù)連接的最大數(shù)量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 設(shè)置了連接可復(fù)用的最大時(shí)間。
sqlDB.SetConnMaxLifetime(10 * time.Second) // 10秒鐘
// 結(jié)構(gòu)體
type List struct {
Name string
State string
Phone string
Email string
Address string
}
// 遷移
db.AutoMigrate(&List{})
// 接口
r := gin.Default()
// 端口號(hào)
PORT := "3001"
r.Run(":" + PORT)
}
定義好之后我們運(yùn)行,沒(méi)有報(bào)錯(cuò)并且在終端顯示出來(lái)3001就是正確的,這個(gè)時(shí)候我們可以去Navicat里面查看crud-list下面的"表",刷新后發(fā)現(xiàn)有一個(gè)lists產(chǎn)生,那就是對(duì)的了。
但是這個(gè)時(shí)候我們存在兩個(gè)問(wèn)題:
- 沒(méi)有主鍵:在struct里添加
gorm.Model來(lái)解決,Ctrl+左鍵可以查看model - 表里面的名稱變成了復(fù)數(shù):詳見(jiàn)文檔的高級(jí)主題-GORM配置里,在
*db*, *err* *:=* gorm.Open(mysql.Open(dsn), *&*gorm.Config{})里面添加一段話即可
更改完成之后我們要先在Navicat里面把原來(lái)的表lists刪掉才能重新創(chuàng)建,這個(gè)時(shí)候我們重新運(yùn)行,就會(huì)發(fā)現(xiàn)表單里面多了很多東西
結(jié)構(gòu)體定義與優(yōu)化
例如:
`gorm:"type:varchar(20); not null" json:"name" binding:"required"`
需要注意的是:
- 結(jié)構(gòu)體里面的變量(Name)必須首字母大寫(xiě),否則創(chuàng)建不出列,會(huì)被自動(dòng)忽略
- gorm指定類(lèi)型
- json表示json接收的時(shí)候的名稱
- binding required表示必須傳入
CRUD接口
// 測(cè)試
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "請(qǐng)求成功",
})
})
編寫(xiě)完這一段之后運(yùn)行代碼,然后去postman里面新建一個(gè)GET接口127.0.0.1:3001然后send一下,出現(xiàn)請(qǐng)求成功就請(qǐng)求成功了。
增也是一樣,寫(xiě)好之后直接用如下JSON來(lái)測(cè)試就可以:
{
"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": "添加成功"
}
這時(shí)候也可以在數(shù)據(jù)庫(kù)里看到這條數(shù)據(jù)
刪除也是一樣,編寫(xiě)完運(yùn)行之后添加一個(gè)DELETE接口,然后輸入127.0.0.1:3001/user/delete/2之后send就可以看到返回了(前提是有數(shù)據(jù))
{
"code": 200,
"msg": "刪除成功"
}
如果是刪除了不存在的id,就會(huì)返回
{
"code": 400,
"msg": "id沒(méi)有找到,刪除失敗"
}
順帶一提,事實(shí)上這個(gè)代碼還可以優(yōu)化,這里的if else太多了,后面優(yōu)化的時(shí)候有錯(cuò)誤直接return
修改也是一樣,示例:
{
"name" : "張三",
"state" : "離職",
"phone" : "13900000000",
"email" : "6666@qq.com",
"address" : "二仙橋成華大道"
}
返回:
{
"code": 200,
"msg": "修改成功"
}
查詢分為兩種:
- 條件查詢
- 分頁(yè)查詢
條件查詢的話,直接寫(xiě)好了請(qǐng)求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": "查詢成功"
}
全部 / 分頁(yè)查詢的話
譬如說(shuō)請(qǐng)求是:127.0.0.1:3001/user/list?pageNum=1&pageSize=2
意思就是查詢第一頁(yè)的兩個(gè)
返回:
{
"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": "查詢成功"
}
如果請(qǐng)求是: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() {
// 如何連接數(shù)據(jù)庫(kù) ? MySQL + Navicat
// 需要更改的內(nèi)容:用戶名,密碼,數(shù)據(jù)庫(kù)名稱
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 設(shè)置空閑連接池中連接的最大數(shù)量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 設(shè)置打開(kāi)數(shù)據(jù)庫(kù)連接的最大數(shù)量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 設(shè)置了連接可復(fù)用的最大時(shí)間。
sqlDB.SetConnMaxLifetime(10 * time.Second) // 10秒鐘
// 結(jié)構(gòu)體
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()
// 測(cè)試
// r.GET("/", func(c *gin.Context) {
// c.JSON(200, gin.H{
// "message": "請(qǐng)求成功",
// })
// })
// 業(yè)務(wù)碼約定:正確200,錯(cuò)誤400
// 增
r.POST("/user/add", func(ctx *gin.Context) {
// 定義一個(gè)變量指向結(jié)構(gòu)體
var data List
// 綁定方法
err := ctx.ShouldBindJSON(&data)
// 判斷綁定是否有錯(cuò)誤
if err != nil {
ctx.JSON(200, gin.H{
"msg": "添加失敗",
"data": gin.H{},
"code": "400",
})
} else {
// 數(shù)據(jù)庫(kù)的操作
db.Create(&data) // 創(chuàng)建一條數(shù)據(jù)
ctx.JSON(200, gin.H{
"msg": "添加成功",
"data": data,
"code": "200",
})
}
})
// 刪
// 1. 找到對(duì)應(yīng)的id對(duì)應(yīng)的條目
// 2. 判斷id是否存在
// 3. 從數(shù)據(jù)庫(kù)中刪除 or 返回id沒(méi)有找到
// Restful編碼規(guī)范
r.DELETE("/user/delete/:id", func(ctx *gin.Context) {
var data []List
// 接收id
id := ctx.Param("id") // 如果有鍵值對(duì)形式的話用Query()
// 判斷id是否存在
db.Where("id = ? ", id).Find(&data)
if len(data) == 0 {
ctx.JSON(200, gin.H{
"msg": "id沒(méi)有找到,刪除失敗",
"code": 400,
})
} else {
// 操作數(shù)據(jù)庫(kù)刪除(刪除id所對(duì)應(yīng)的那一條)
// db.Where("id = ? ", id).Delete(&data) <- 其實(shí)不需要這樣寫(xiě),因?yàn)椴榈降膁ata里面就是要?jiǎng)h除的數(shù)據(jù)
db.Delete(&data)
ctx.JSON(200, gin.H{
"msg": "刪除成功",
"code": 200,
})
}
})
// 改
r.PUT("/user/update/:id", func(ctx *gin.Context) {
// 1. 找到對(duì)應(yīng)的id所對(duì)應(yīng)的條目
// 2. 判斷id是否存在
// 3. 修改對(duì)應(yīng)條目 or 返回id沒(méi)有找到
var data List
id := ctx.Param("id")
// db.Where("id = ?", id).Find(&data) 可以這樣寫(xiě),也可以寫(xiě)成下面那樣
// 還可以再Where后面加上Count函數(shù),可以查出來(lái)這個(gè)條件對(duì)應(yīng)的條數(shù)
db.Select("id").Where("id = ? ", id).Find(&data)
if data.ID == 0 {
ctx.JSON(200, gin.H{
"msg": "用戶id沒(méi)有找到",
"code": 400,
})
} else {
// 綁定一下
err := ctx.ShouldBindJSON(&data)
if err != nil {
ctx.JSON(200, gin.H{
"msg": "修改失敗",
"code": 400,
})
} else {
// db修改數(shù)據(jù)庫(kù)內(nèi)容
db.Where("id = ?", id).Updates(&data)
ctx.JSON(200, gin.H{
"msg": "修改成功",
"code": 200,
})
}
}
})
// 查
// 第一種:條件查詢,
r.GET("/user/list/:name", func(ctx *gin.Context) {
// 獲取路徑參數(shù)
name := ctx.Param("name")
var dataList []List
// 查詢數(shù)據(jù)庫(kù)
db.Where("name = ? ", name).Find(&dataList)
// 判斷是否查詢到數(shù)據(jù)
if len(dataList) == 0 {
ctx.JSON(200, gin.H{
"msg": "沒(méi)有查詢到數(shù)據(jù)",
"code": "400",
"data": gin.H{},
})
} else {
ctx.JSON(200, gin.H{
"msg": "查詢成功",
"code": "200",
"data": dataList,
})
}
})
// 第二種:全部查詢 / 分頁(yè)查詢
r.GET("/user/list", func(ctx *gin.Context) {
var dataList []List
// 查詢?nèi)繑?shù)據(jù) or 查詢分頁(yè)數(shù)據(jù)
pageSize, _ := strconv.Atoi(ctx.Query("pageSize"))
pageNum, _ := strconv.Atoi(ctx.Query("pageNum"))
// 判斷是否需要分頁(yè)
if pageSize == 0 {
pageSize = -1
}
if pageNum == 0 {
pageNum = -1
}
offsetVal := (pageNum - 1) * pageSize // 固定寫(xiě)法 記住就行
if pageNum == -1 && pageSize == -1 {
offsetVal = -1
}
// 返回一個(gè)總數(shù)
var total int64
// 查詢數(shù)據(jù)庫(kù)
db.Model(dataList).Count(&total).Limit(pageSize).Offset(offsetVal).Find(&dataList)
if len(dataList) == 0 {
ctx.JSON(200, gin.H{
"msg": "沒(méi)有查詢到數(shù)據(jù)",
"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,
},
})
}
})
// 端口號(hào)
PORT := "3001"
r.Run(":" + PORT)
}到此這篇關(guān)于Gin+Gorm實(shí)戰(zhàn)CRUD的文章就介紹到這了,更多相關(guān)Gin Gorm CRUD內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang time包做時(shí)間轉(zhuǎn)換操作
這篇文章主要介紹了golang time包做時(shí)間轉(zhuǎn)換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
使用golang腳本基于kubeadm創(chuàng)建新的token(問(wèn)題分析)
這篇文章主要介紹了使用golang腳本基于kubeadm創(chuàng)建新的token(問(wèn)題分析),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-10-10
詳解Golang如何實(shí)現(xiàn)支持隨機(jī)刪除元素的堆
堆是一種非常常用的數(shù)據(jù)結(jié)構(gòu),它能夠支持在O(1)的時(shí)間復(fù)雜度獲取到最大值(或最小值)。本文主要介紹了如何實(shí)現(xiàn)支持O(log(n))隨機(jī)刪除元素的堆,需要的可以參考一下2022-09-09
Go的gin參數(shù)校驗(yàn)中的validator庫(kù)詳解
這篇文章主要介紹了Go的gin參數(shù)校驗(yàn)之validator庫(kù),使用 validator 以后,只需要在定義結(jié)構(gòu)體時(shí)使用 binding 或 validate tag標(biāo)識(shí)相關(guān)校驗(yàn)規(guī)則,就可以進(jìn)行參數(shù)校驗(yàn)了,而不用自己?jiǎn)为?dú)去寫(xiě)常見(jiàn)的校驗(yàn)規(guī)則,需要的朋友可以參考下2023-08-08
golang 切片的三種使用方式及區(qū)別的說(shuō)明
這篇文章主要介紹了golang 切片的三種使用方式及區(qū)別的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04

