【Go 入门】CRUD 实战:增删改查,一篇讲透
上一篇我们把数据存进了数据库。这篇只干一件事:把最核心的四个操作——增、删、改、查(CRUD)讲透。
0. CRUD 是什么?
CRUD 是四个单词的缩写,所有软件都离不开这四个操作:
| 字母 | 全称 | 中文 | 举个例子 |
|---|---|---|---|
| C | Create | 增 | 登记一本新书 |
| R | Read | 查 | 查看书单 |
| U | Update | 改 | 修改书的价格 |
| D | Delete | 删 | 下架一本书 |
类比:你逛的购物 App、刷的论坛,背后都是这四个操作。学会 CRUD,后端开发就入门了一半。
1. 增删改查 = 四个请求方法
在网页开发里,每个操作对应一个固定的"请求方法":
| 操作 | 请求方法 | 路径 | 干什么 |
|---|---|---|---|
| 增 | POST | /api/books | 加一本书 |
| 查 | GET | /api/books | 看书单 |
| 改 | PUT | /api/books/:id | 改某本书 |
| 删 | DELETE | /api/books/:id | 删某本书 |
记忆口诀:POST 加,GET 看,PUT 改,DELETE 删。
2. 准备工作
新建一个项目,三步:
mkdir mybooks
cd mybooks
go mod init mybooks
go get github.com/gin-gonic/gin
go get gorm.io/gorm
go get github.com/glebarez/sqlite
第三个库 glebarez/sqlite 是纯 Go 的 SQLite 驱动,Windows 不用装编译器(上篇讲过)。
3. 全部代码(就一个 main.go)
在项目里新建 main.go,复制下面全部内容:
package main
import (
"log"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
// Book 书的结构体,对应数据库里的 books 表
type Book struct {
ID uint `json:"id" gorm:"primaryKey"`
Title string `json:"title"`
Author string `json:"author"`
Price float64 `json:"price"`
}
func main() {
// ===== 1. 连接数据库(books.db 就是一个文件)=====
db, err := gorm.Open(sqlite.Open("books.db"), &gorm.Config{})
if err != nil {
log.Fatal("数据库连接失败:", err)
}
db.AutoMigrate(&Book{}) // 自动建表,没有 books 表就创建
r := gin.Default()
// ===== 2. 增:POST /api/books =====
r.POST("/api/books", func(c *gin.Context) {
var b Book
// 前端发来的 JSON 填进 b
if err := c.ShouldBindJSON(&b); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.Create(&b) // 存进数据库,b.ID 自动填上
c.JSON(http.StatusOK, gin.H{"data": b})
})
// ===== 3. 查:GET /api/books(全部)=====
r.GET("/api/books", func(c *gin.Context) {
var books []Book
db.Find(&books) // 查出所有书
c.JSON(http.StatusOK, gin.H{"data": books})
})
// ===== 4. 查:GET /api/books/1(单个)=====
r.GET("/api/books/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id")) // 路径里的 1 是字符串,转成数字
var b Book
if err := db.First(&b, id).Error; err != nil { // 按 id 查
c.JSON(http.StatusNotFound, gin.H{"error": "没有这本书"})
return
}
c.JSON(http.StatusOK, gin.H{"data": b})
})
// ===== 5. 改:PUT /api/books/1 =====
r.PUT("/api/books/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var b Book
if err := db.First(&b, id).Error; err != nil { // 先查出这本书
c.JSON(http.StatusNotFound, gin.H{"error": "没有这本书"})
return
}
if err := c.ShouldBindJSON(&b); err != nil { // 再填进新内容
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.Save(&b) // 保存修改
c.JSON(http.StatusOK, gin.H{"data": b})
})
// ===== 6. 删:DELETE /api/books/1 =====
r.DELETE("/api/books/:id", func(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
db.Delete(&Book{}, id) // 按 id 删除
c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
})
log.Println("服务启动:http://localhost:8080")
r.Run(":8080")
}
核心就 5 个动作,记住这 5 行:
| 想做什么 | 关键一行 | 说明 |
|---|---|---|
| 增 | db.Create(&b) | 插进数据库 |
| 查全部 | db.Find(&books) | 查出所有记录 |
| 查单个 | db.First(&b, id) | 按 id 查一条 |
| 改 | db.Save(&b) | 保存修改 |
| 删 | db.Delete(&Book{}, id) | 按 id 删除 |
每个操作都传了
&(地址),原因和上一篇ShouldBindJSON(&t)一样:要让函数真的改到我们的变量,必须告诉它变量放在哪。
4. 跑起来测一测
启动:
go run .
另开一个终端,按顺序敲:
# 增:加两本书
curl -X POST http://localhost:8080/api/books -H "Content-Type: application/json" -d '{"title":"Go 入门","author":"阿明","price":39.9}'
curl -X POST http://localhost:8080/api/books -H "Content-Type: application/json" -d '{"title":"Gin 实战","author":"小红","price":49.9}'
# 查全部
curl http://localhost:8080/api/books
# 查第 1 本
curl http://localhost:8080/api/books/1
# 改:把第 1 本价格改成 29.9
curl -X PUT http://localhost:8080/api/books/1 -H "Content-Type: application/json" -d '{"price":29.9}'
# 删:删掉第 2 本
curl -X DELETE http://localhost:8080/api/books/2
# 再看列表,应该只剩第 1 本,价格变成 29.9
curl http://localhost:8080/api/books
全走通,你的第一个完整增删改查就完成了。重启程序(Ctrl+C 再 go run .)再查一次,数据还在——因为存进了 books.db 文件。
5. 我踩过的 3 个坑
- 忘记写
&:db.Create(&b)、db.Find(&books)、db.First(&b, id),不写 & 就是白干(函数改不到你的变量) - 改数据用了 Create:改要用 Save,Create 是新增,会把一本书存成两本
- Windows 用了官方 SQLite 驱动:
gorm.io/driver/sqlite要装编译器,用github.com/glebarez/sqlite直接跑
6. 总结
CRUD = 增(POST + Create)、查(GET + Find/First)、改(PUT + Save)、删(DELETE + Delete)。
真实项目里,代码会像系列第一篇那样拆成多个文件(model、handler、main),但核心永远是这 5 行数据库操作。把这篇跑通,你已经会写后端接口了。
下一篇可以给接口加登录功能(JWT 鉴权),或者讲讲多张表怎么关联。想看哪个评论区告诉我~
参考资料
- GORM 官方文档(中文)— https://gorm.io/zh_CN/docs/
- Gin 官方文档(中文)— https://gin-gonic.com/zh-cn/docs/
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2302_79547686/article/details/165007459




