【go从零单排】gin+gorm理解及实现CRUD
🌈Don’t worry , just coding!
内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。
📗概念
GIN
Gin 是一个高性能的 Go 语言 Web 框架,专为构建 RESTful API 和 Web 应用而设计。它以简洁的 API 和高效的性能著称,适合用于构建快速、可扩展的 Web 服务。Gin 基于 net/http 包构建,提供了许多功能,如中间件支持、路由分组、JSON 验证、错误处理等。
GORM
GORM 是一个流行的 Go 语言 ORM(对象关系映射)库,它提供了一个简单且强大的方式来与数据库进行交互。GORM 支持多种数据库,如 MySQL、PostgreSQL、SQLite 和 SQL Server。它允许开发者使用 Go 语言的结构体来表示数据库表,并通过方法调用来执行 CRUD(创建、读取、更新、删除)操作。
下载
官网下载
- go get -u github.com/gin-gonic/gin 在国内会超时无法下载,需要科学上网
国内下载
- go env -w GO111MODULE=on
- go env -w GOPROXY=https://goproxy.cn,direct
- go mod init YourProjectName
- go get -u github.com/gin-gonic/gin
- go get -u gorm.io/gorm
- go get -u gorm.io/driver/sqlite // 安装 SQLite 驱动
💻代码
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"net/http"
)
// 定义用户模型
// User 结构体表示用户模型,包含 ID、Name 和 Email 字段。
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
Name string `json:"name"`
Email string `json:"email"`
}
// 初始化数据库
func setupDatabase() *gorm.DB {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{}) // 自动迁移
return db
}
// 创建用户
func createUser(c *gin.Context) { //参数:c *gin.Context 是 Gin 框架提供的上下文对象,包含请求和响应的相关信息。
//数据库初始化:调用 setupDatabase() 函数,连接到 SQLite 数据库并返回数据库实例 db。
db := setupDatabase()
//定义变量:创建一个 User 类型的变量 user,用于存储从请求中绑定的数据。
var user User
//c.ShouldBindJSON(&user):尝试将请求体中的 JSON 数据绑定到 user 变量。
//如果请求体不符合预期格式,ShouldBindJSON 将返回错误。
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
//创建记录:使用 GORM 的 Create 方法将 user 变量中的数据插入到数据库中。
db.Create(&user)
//成功响应:如果用户创建成功,返回 HTTP 状态码 200 OK 和新创建的用户数据(包括自动生成的 ID 等信息)。
c.JSON(http.StatusOK, user)
}
// 获取所有用户
// c *gin.Context 是 Gin 框架提供的上下文对象,包含请求和响应的相关信息。
func getUsers(c *gin.Context) {
db := setupDatabase()
//创建一个切片 users,类型为 User,用于存储从数据库中查询到的用户记录。
var users []User
//使用 GORM 的 Find 方法查询所有用户记录,并将结果存储到 users 切片中。Find 方法会自动填充切片中的数据。
db.Find(&users)
//如果查询成功,返回 HTTP 状态码 200 OK 和查询到的用户数据(users 切片)
c.JSON(http.StatusOK, users)
}
// 根据 ID 查询用户
func getUserByID(c *gin.Context) {
db := setupDatabase()
//从 URL 路径中获取用户的 ID。假设你的路由是 /users/:id,c.Param("id") 将提取该 ID。
id := c.Param("id") // 从 URL 路径中获取用户 ID
var user User
//使用 GORM 的 First 方法根据 ID 查询用户。如果用户存在,user 变量将被填充;如果找不到,err 将不为 nil。
if err := db.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户未找到"})
return
}
c.JSON(http.StatusOK, user) // 返回用户信息
}
// 更新用户
// updateUser,用于处理更新用户信息的请求。
// updateUser,用于处理更新用户信息的请求。
func updateUser(c *gin.Context) {
db := setupDatabase()
var user User
//c.ShouldBindJSON(&user):尝试将请求体中的 JSON 数据绑定到 user 变量。
//如果请求体不符合预期格式,ShouldBindJSON 将返回错误。
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
//使用 GORM 的 Where 方法找到 ID 为 user.ID 的记录,并使用 Updates 方法更新该用户的所有字段。
if err := db.Where("id = ?", user.ID).Updates(user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "更新失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, user)
}
// 更新用户的 email 字段为空
func updateEmail(c *gin.Context) {
db := setupDatabase()
id := c.Param("id") // 从 URL 中获取用户 ID
DefaultEmail := "www.example.com"
// 创建一个更新结构体,只包含需要更新的字段
updateData := struct {
Email *string `json:"email"` // 使用指针类型,可以设置为 nil
}{
Email: &DefaultEmail, // 设置 email 为 DefaultEmail
}
// 执行更新操作
if err := db.Model(&User{}).Where("id = ?", id).Updates(updateData).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "更新失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "用户 email 已设置为指定Email"})
}
// 删除用户
func deleteUser(c *gin.Context) {
db := setupDatabase()
id := c.Param("id")
//&User{}:这里传入的是一个 User 结构体的指针。GORM 需要知道要删除哪个模型的记录。
//id:这是要删除的记录的主键(通常是用户的 ID)。GORM 会根据这个 ID 找到对应的记录并进行删除。
if err := db.Delete(&User{}, id).Error; err != nil {
//如果 db.Delete(...) 返回了一个错误(即 err 不为 nil),则进入 if 语句块,通常会处理错误情况,比如返回一个 JSON 响应给客户端,表示删除失败。
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "用户已删除"})
}
func main() {
r := gin.Default()
// 定义路由
r.POST("/users", createUser) // 创建用户
r.GET("/users", getUsers) // 获取所有用户
r.PUT("/users", updateUser) // 更新用户
r.DELETE("/users/:id", deleteUser) // 删除用户
r.GET("/users/:id", getUserByID) //根据ID查询用户
r.PUT("/users/:id", updateEmail) //根据ID跟新用户指定字段
// 启动服务器
r.Run(":9080")
}
🔍理解
GROM
准备工作
- 初始化数据库连接
package main
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"log"
)
func setupDatabase() *gorm.DB {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
log.Fatal("failed to connect to the database:", err)
}
return db
}
- 定义模型
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100"`
Email string `gorm:"uniqueIndex"`
}
- 使用 GORM 的自动迁移功能创建表
func migrate(db *gorm.DB) {
db.AutoMigrate(&User{})
}
CRUD 操作示例
- 创建记录:
func createUser(db *gorm.DB, name string, email string) {
user := User{Name: name, Email: email}
db.Create(&user)
}
读取记录:
复制
func getUser(db *gorm.DB, id uint) User {
var user User
db.First(&user, id) // 根据 ID 查找用户
return user
}
- 更新记录:
func updateUserEmail(db *gorm.DB, id uint, newEmail string) {
var user User
db.First(&user, id) // 查找用户
user.Email = newEmail
db.Save(&user) // 保存更新
}
- 删除记录:
func deleteUser(db *gorm.DB, id uint) {
db.Delete(&User{}, id) // 根据 ID 删除用户
}
- 事务示例
func performTransaction(db *gorm.DB) {
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback() // 回滚事务
}
}()
// 执行操作
if err := tx.Create(&User{Name: "John", Email: "john@example.com"}).Error; err != nil {
tx.Rollback()
return
}
tx.Commit() // 提交事务
}
GIN
- 安装 Gin
go get -u github.com/gin-gonic/gin
- 创建基本的 Gin 应用
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个默认的 Gin 路由引擎
r := gin.Default()
// 定义一个简单的 GET 路由
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, World!",
})
})
// 启动服务
r.Run(":8080") // 在 8080 端口启动服务
}
- 路由示例
- 定义多个路由:
r.GET("/users", getUsers)
r.POST("/users", createUser)
r.PUT("/users/:id", updateUser)
r.DELETE("/users/:id", deleteUser)
- 路由处理函数:
func getUsers(c *gin.Context) {
// 处理获取用户的逻辑
}
func createUser(c *gin.Context) {
// 处理创建用户的逻辑
}
func updateUser(c *gin.Context) {
id := c.Param("id")
// 处理更新用户的逻辑
}
func deleteUser(c *gin.Context) {
id := c.Param("id")
// 处理删除用户的逻辑
}
- 使用中间件
Gin 支持中间件,可以在请求处理前后执行特定的逻辑。
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
// 处理请求前的逻辑
log.Println("Request received")
c.Next() // 调用下一个中间件或处理函数
// 处理请求后的逻辑
log.Println("Request completed")
}
}
// 在路由组中使用中间件
r.Use(Logger())
- JSON 处理
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 处理用户创建逻辑
c.JSON(201, user)
}
- 错误处理
Gin 提供的错误处理机制:
func getUser(c *gin.Context) {
id := c.Param("id")
user, err := findUserByID(id)
if err != nil {
c.JSON(404, gin.H{"error": "User not found"})
return
}
c.JSON(200, user)
}
sqlite
- SQLite 是一个轻量级的数据库,很多 Go 语言的 ORM(如 GORM)已经将 SQLite 的驱动程序包含在内。
- SQLite 文件:当你在代码中指定数据库文件名(如 test.db)时,SQLite 会自动创建该文件。因此,你只需确保你的应用程序有权限在指定目录中创建文件。
- 无需单独安装 SQLite,只需确保在你的 Go 项目中安装 GORM 和 SQLite 驱动即可。
💡 Tips
Gin 是一个高性能的 Go 语言 Web 框架,具有以下特点:
- 高性能:Gin 使用了 httprouter,具有极快的路由速度。
- 易用性:提供了简单易用的 API,方便开发者快速上手。
- 中间件支持:可以轻松添加中间件,支持日志、认证等功能。
- JSON 验证:内置 JSON 验证功能,简化请求参数的处理。
- 丰富的文档:提供详细的文档和示例,帮助开发者理解和使用。
💪无人扶我青云志,我自踏雪至山巅。