使用 GORM实现增删改查操作 | 青训营

127 阅读6分钟

这是我参与「第六届青训营 -后端场」笔记创作活动写下的第4篇笔记。

一、安装GORM库

首先,我们需要在Go项目中安装GORM库。可以使用以下命令进行安装:

 go get -u gorm.io/gorm
 go get -u gorm.io/driver/mysql

/导入包之前否则显示标红/

二、连接数据库

在使用GORM之前,我们需要先连接到数据库。

以MySQL为例,连接数据库的步骤如下:

1、创建一个数据库:

  • 设置用户名和密码以及连接名,后续会用

image.png

  • 新建数据库

image.png

2、导入所需的包:

 import (
     "gorm.io/gorm"
     "gorm.io/driver/mysql"
 )

/在go语言中引入一个包,如果没有使用,需要添加下划线,否则会报错/

例如:

 _"github.com/go-sql-driver-mysql"
 "github.com/jinzhu/gorm"
 _"gorm-1/testA"

添加下划线还有一个作用:可以初始化init()函数

在启动程序在main()之前会先被调用

3、创建数据库连接:

 dsn := "username:password@tcp(127.0.0.1:3306)/database_name?charset=utf8mb4&parseTime=True&loc=Local"
 db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
 if err != nil {
     // 处理连接错误
 }
 ​

/其中,dsn是数据库连接字符串,username为用户名,password为用户密码,database_name为数据库名/

三、定义结构体模型

接下来,我们需要定义数据库表对应的模型结构体。例如,我们创建一个empolyee模型表示员工信息:

 type employee struct {
     Id int
     Name string
     Age int
 }

四、创建表结构

在GORM中,可以使用AutoMigrate方法自动创建数据库表。在应用程序的入口处调用该方法即可:

 ​
 db.AutoMigrate(&User{})

五、尝试运行

双击打开我们创建的数据库,会发现在"表"里已经出现了一个名为employees的表格

image.png

也可以创建单表,在26行后添加一句

 ​
 sqlDB.SingularTable(true)
 //开启单表属性

完整代码为:

 package main
 ​
 import (
     "fmt"
     "gorm.io/driver/mysql"
     "gorm.io/gorm"
 )
 type employee struct {
     Id int
     Name string
     Age int
 }
 ​
 func main() {
     dsn := "root:123456@tcp(127.0.0.1:3306)/pract-list?charset=utf8mb4&parseTime=True&loc=Local"
     db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
     if err != nil {
         fmt.Println("gorm.Open:", err)
         return
     }
     sqlDB, err := db.DB()
     if err != nil {
         fmt.Println("db.DB:", err)
         return
     }
     defer sqlDB.Close()
     fmt.Println(db.AutoMigrate(new(employee)).Error)
 }
 ​

六、gorm构建连接池

使用 GORM 构建连接池非常简单。GORM 库已经集成了连接池的功能,我们只需通过配置参数来设置连接池的大小和其他相关属性。

gorm构建连接池主要涉及三个步骤:

  • 定义全局变量
 var DB *gorm.DB
  • 新建变量接收用gorm.Open方法构建连接池的句柄
  • 修改属性

我们使用 db.DB() 获取 GORM 的底层 *sql.DB,然后可以调用其方法来设置连接池的大小和其他属性。

SetMaxOpenConns():设置最大打开连接数,即同时最大可以有多少个连接到数据库,默认为0(表示无限制)。

SetMaxIdleConns():设置最大空闲连接数,即连接池中最大可以空闲的连接数,默认为2。

SetConnMaxLifetime():设置连接的最大生命周期,即连接在连接池中的最长存活时间,默认为0(表示永久存活)。

     // 设置连接池大小
     sqlDB.SetMaxOpenConns(100) // 设置最大打开连接数
     sqlDB.SetMaxIdleConns(10)  // 设置最大空闲连接数
     sqlDB.SetConnMaxLifetime(0) // 设置连接的最大生命周期

应该始终在使用完数据库连接后将其释放,所以最后我们使用 defer sqlDB.Close() 来确保连接在主函数结束时被关闭。

七、实现增删改查操作

1、创建记录(插入数据):

     var emp employee
     emp.Name = "小王"
     emp.Age = 23
     res:=db.Create(&emp)
     fmt.Println(emp.Id)
     fmt.Println(res.Error)
     fmt.Println(res.RowsAffected)

声明一个名为emp的变量,并对NameAge进行赋值。

image.png

2、更新数据

  • 指定id更新字段
     var emp employee
     emp.Name = "阿红"
     emp.Age = 24
     emp.Id = 1
     res :=db.Save(&emp)
  • 条件更新
 res :=db.Model(new(employee)).Where("name=?","阿红").Update("name","小二")

//这里是将name为”小红“的信息都修改为”小二“

  • 多个字段更新
     var emp employee
     emp.Id = 2
     res:=db.Model(&emp).Updates(map[string]interface{}{"name":"阿彬","age":18})

//这句可以实现修改多个数据

3、查询数据

获取第一条,按主键排序

     db.First(&emp)

获取最后一条

 db.Last(&emp)

如果需要查询多条记录,可以使用 Find 方法,以及将结果存储到 employees 切片中。

 var emp []employee
     db.Find(&emp)

使用 Select 方法可以指定要选择的字段

 ​
     db.Select("name").First(&emp)

4、删除数据

主键删除

 res := db.Delete(&emp)

八、结合gin封装增删查改

初始化引擎,以及路由注册初始化

     r := gin.Default()
 ​
     r.POST("/employees", createEmployee)
     r.GET("/employees/:id", getEmployee)
     r.PUT("/employees/:id", updateEmployee)
     r.DELETE("/employees/:id", deleteEmployee)

1、增加操作:

  • 在 Gin 中,创建一个路由处理函数,该函数接收客户端传递的数据,并将其绑定到结构体中。
  • 使用 DB.Create(&emp) 执行插入操作,并将插入的结果保存在 result 变量中。
  • 检查 result.Error 是否为空,如果非空,则表示插入出现错误,可以返回相应的错误响应给客户端。否则,返回成功的响应。

2、查询操作:

  • 在 Gin 中,创建一个路由处理函数,该函数根据员工 ID 参数从 URL 中获取要查询的员工 ID。

  • 使用 DB.First(&emp, id) 执行查询操作,并将结果保存在 result 变量中。其中,&emp 表示查询结果将保存到 emp 变量中,id 是要查询的员工 ID。

  • 检查 result.Error 是否为空,如果非空,则表示查询出现错误,可以返回相应的错误响应给客户端。否则,返回查询到的员工信息作为成功响应。

    例如:

     func getEmployee(c *gin.Context) {
         id := c.Param("id")
     ​
         var emp Employee
         if result := DB.First(&emp, id); result.Error != nil {
             c.JSON(http.StatusNotFound, gin.H{"error": "Employee not found"})
             return
         }
     ​
         c.JSON(http.StatusOK, gin.H{"data": emp})
     }
    

3、更新操作:

  • 在 Gin 中,创建一个路由处理函数,该函数根据员工 ID 参数从 URL 中获取要更新的员工 ID。
  • 使用 DB.First(&emp, id) 执行查询操作,以获取要更新的员工信息。
  • 使用 c.ShouldBindJSON(&emp) 将客户端传递的更新数据绑定到结构体中。
  • 使用 DB.Save(&emp) 执行更新操作,并将更新的结果保存在 result 变量中。
  • 检查 result.Error 是否为空,如果非空,则表示更新出现错误,可以返回相应的错误响应给客户端。否则,返回更新后的员工信息作为成功响应。

4、删除操作:

  • 在 Gin 中,创建一个路由处理函数,该函数根据员工 ID 参数从 URL 中获取要删除的员工 ID。
  • 使用 DB.First(&emp, id) 执行查询操作,以获取要删除的员工信息。
  • 使用 DB.Delete(&emp) 执行删除操作,并将删除的结果保存在 result 变量中。
  • 检查 result.Error 是否为空,如果非空,则表示删除出现错误,可以返回相应的错误响应给客户端。否则,返回删除成功的消息作为成功响应。
 func deleteEmployee(c *gin.Context) {
     id := c.Param("id")
 ​
     var emp Employee
     if result := DB.First(&emp, id); result.Error != nil {
         c.JSON(http.StatusNotFound, gin.H{"error": "Employee not found"})
         return
     }
 ​
     if result := DB.Delete(&emp); result.Error != nil {
         c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
         return
     }
 ​
     c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Employee %d deleted", emp.ID)})
 }

参考资料:

Database/sql 及 GORM 相关解读 - 掘金 (juejin.cn)

gorm框架初步结合gin封装增删查改方法