当前位置: 首页 > article >正文

【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

  1. 安装 Gin
go get -u github.com/gin-gonic/gin
  1. 创建基本的 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 端口启动服务
}
  1. 路由示例
  • 定义多个路由:
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")
    // 处理删除用户的逻辑
}
  1. 使用中间件
    Gin 支持中间件,可以在请求处理前后执行特定的逻辑。
func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 处理请求前的逻辑
        log.Println("Request received")

        c.Next() // 调用下一个中间件或处理函数

        // 处理请求后的逻辑
        log.Println("Request completed")
    }
}


// 在路由组中使用中间件
r.Use(Logger())
  1. 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)
}
  1. 错误处理
    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 验证功能,简化请求参数的处理。
  • 丰富的文档:提供详细的文档和示例,帮助开发者理解和使用。

💪无人扶我青云志,我自踏雪至山巅。
在这里插入图片描述


http://www.kler.cn/a/393246.html

相关文章:

  • 家政预约小程序数据库设计
  • Unittest02|TestSuite、TestRunner、HTMLTestRunner、处理excel表数据、邮件接收测试结果
  • 谷歌Gemini与Anthropic Claude对比测试引发争议:AI竞赛暗流涌动
  • 源码分析之Openlayers中GeometryCollection类
  • Flink调优----反压处理
  • Python OCR 文字识别
  • 机器学习系列----KNN分类
  • 【Linux网络】Linux网络编程套接字,UDP与TCP
  • PCB安全电气间距
  • Python网络爬虫与数据采集实战——网络协议与HTTP
  • linux命令详解,存储管理相关
  • 排序算法 -堆排序
  • SQL面试题——奔驰SQL面试题 车辆在不同驾驶模式下的时间
  • 学Linux的第八天
  • 数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目)
  • uniapp 上传 base64 图片
  • ubuntu22.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法)
  • 【二叉搜素树】——LeetCode二叉树问题集锦:6个实用题目和解题思路
  • 除了 Postman,还有什么好用的 API 测试工具吗
  • uni-app中使用 unicloud 云开发平台③
  • C++生成随机数
  • 信用租赁系统的灵活配置与智能化管理助力租赁市场发展
  • 29系统备份与恢复
  • 深入理解 Vue v-model 原理与应用
  • 量化交易系统开发-实时行情自动化交易-4.1.1.A股趋势跟踪交易策略实现
  • 批量缓存模版