使用 GORM 连接 MySQL 并进行增删改查操作 | 豆包MarsCode AI刷题

66 阅读5分钟

一、Go 语言与 ORM 简介

Go 是一种开源的编程语言,它具有高效、简洁、并发性能强等特点,在后端开发、云计算、分布式系统等领域得到广泛应用。

对象关系映射(Object Relational Mapping,简称 ORM)是一种编程技术,它允许开发者使用面向对象的编程语言来操作关系型数据库,而无需编写大量的原生 SQL 语句。通过 ORM,开发者可以将数据库表映射为编程语言中的对象,对对象的操作会自动转换为对数据库的操作,大大提高了开发效率和代码的可维护性。

二、Go 的 ORM 库概述

Go 语言中有多个 ORM 库可供选择,常见的有以下几个:

  1. GORM:功能强大且灵活,支持多种数据库,如 MySQL、PostgreSQL、SQLite 等,具有丰富的功能,如关联查询、事务处理、钩子函数等,是目前使用较为广泛的 Go ORM 库。

  2. Xorm:简单易用,对数据库的操作提供了简洁的 API,也支持多种数据库,在一些项目中也有应用。

  3. Bee ORM:以简单快速著称,能够快速进行数据库开发,但功能相对 GORM 可能稍显逊色。

GORM 功能强大、活跃的社区支持,用的多。

三、使用 GORM 连接 MySQL

以下是使用 GORM 连接 MySQL 数据库的基本步骤:

首先,安装 Go 环境和 MySQL 数据库。go安装gorm框架和驱动

go get -u gorm.io/gorm

go get -u gorm.io/driver/mysql

然后使用以下代码进行连接:

package main

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

func main() {
    // 定义数据库连接字符串,格式为:用户名:密码@(主机地址:端口号)/数据库名?参数
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    // 使用 GORM 的 MySQL 驱动打开数据库连接
    db, err := gorm.Open(mysql.Open(dsn), ```
&gorm.Config{
    NamingStrategy: schema.NamingStrategy{
       TablePrefix:   "",   // 表前缀
       SingularTable: true, // 禁用表名复数
    }})
    if err!= nil {
        panic(err)
    }
    // 这里可以进行后续的数据库操作
}

dsn 包含了连接 MySQL 所需的信息,如用户名、密码、主机地址、端口号、数据库名以及一些字符集和时间解析的参数。gorm.Open 函数使用 mysql.Open 方法传入连接字符串来建立与 MySQL 数据库的连接,并返回一个 gorm.DB 类型的数据库对象,通过该对象可以进行各种数据库操作。

四、GORM 的增删改查操作

(一)定义数据模型

在进行增删改查操作之前,需要先定义与数据库表对应的结构体模型。

type User struct {
    ID   uint   `gorm:"primaryKey"`
    Name string
    Age  int
}

// TableName 指定表名 
func (Stu) TableName() string { return "student" }

也可以通过连接配置指定表名

(二)创建记录(插入操作)

使用 Create 方法向数据库中插入一条记录:

func main() {

    // 创建一个 User 实例
    user := User{Name: "fes", Age: 18}
    // 将 user 插入到数据库中
    result := db.Create(&user)
    if result.Error!= nil {
        panic(result.Error)
    }
    // 插入成功后,user 的 ID 会被自动赋值
    fmt.Println(user.ID)
}

(三)查询记录

  1. 查询单个记录:可以使用 First 或 Take 方法查询单个记录。例如,根据 ID 查询用户:
var user User
// 根据主键查询
db.First(&user, 1) 
// 或者使用 Take 方法
// db.Take(&user, 1) 
if user.ID == 0 {
    fmt.Println("未找到记录")
} else {
    fmt.Printf("用户姓名:%s,年龄:%d\n", user.Name, user.Age)
}

2. 查询多条记录:使用 Find 方法查询多条记录。例如,查询所有用户:

var users []User
db.Find(&users)
for _, u := range users {
    fmt.Printf("用户姓名:%s,年龄:%d\n", u.Name, u.Age)
}

(四)更新记录

使用 Save 或 Updates 方法更新记录。例如,更新用户的年龄:

var user User
db.First(&user, 1)
user.Age = 30
// 使用 Save 方法更新
db.Save(&user) 
// 或者使用 Updates 方法,指定要更新的字段
// db.Model(&user).Updates(User{Age: 30}) 

(五)删除记录

使用 Delete 方法删除记录。例如,删除指定 ID 的用户:

复制

db.Delete(&User{}, 1)

五、GORM 工程化

在实际工程中,首先要规划好项目的目录结构。通常会有一个models目录用于存放数据库模型结构体,一个database目录用于存放数据库连接相关的代码

image.png

package database

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

var DB *gorm.DB

func Connect() {
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    var err error
    DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err!= nil {
        panic(err)
    }
}
package models

import "gorm.io/gorm"

type User struct {
    ID   uint   `gorm:"primaryKey"`
    Name string
    Age  int
    // 可以添加更多字段和标签,如创建时间、更新时间等
    CreatedAt time.Time
    UpdatedAt time.Time
}

业务逻辑处理阶段

-   **创建操作**
func GetUserByID(c *gin.Context) {
    id := c.Param("id")
    var user models.User
    result := database.DB.First(&user, id)
    if result.Error!= nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
        return
    }
    c.JSON(http.StatusOK, user)
}
  • 更新操作

    • 假设要更新用户的年龄,函数可以这样编写:
func UpdateUserAge(c *gin.Context) {
    id := c.Param("id")
    var user models.User
    result := database.DB.First(&user, id)
    if result.Error!= nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
        return
    }
    var updateData struct {
        Age int
    }
    if err := c.BindJSON(&updateData); err!= nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    user.Age = updateData.Age
    result = database.DB.Save(&user)
    if result.Error!= nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error})
        return
    }
    c.JSON(http.StatusOK, user)
}
  • 删除操作

    • 要删除用户的函数如下:
func DeleteUser(c *gin.Context) {
    id := c.Param("id")
    result := database.DB.Delete(&models.User{}, id)
    if result.Error!= nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "用户删除成功"})
}

然后在main.go中启动 HTTP 服务器:

package main

import (
    "myproject/database"
    "myproject/routers"
    "log"
    "net/http"
)

func main() {
    database.Connect()
    router := routers.SetupRoutes()
    log.Fatal(http.ListenAndServe(":8080", router))
}

六、GORM 的连接池池化功能

GORM 使用 database/sql 标准库的连接池功能。在 gorm.io/driver/mysql 包内部,当创建数据库连接时,会基于 database/sql 的连接池机制进行连接的管理。

database/sql 的连接池默认会维护一定数量的空闲连接,当有数据库操作请求时,如果有空闲连接则直接使用,否则会创建新的连接,直到达到最大连接数限制。连接在使用完成后会被放回连接池,供后续请求复用。

可以通过 database/sql 提供的一些函数和参数来配置连接池的行为,例如设置最大空闲连接数、最大连接数、连接的生命周期等。在 GORM 通过 gorm.Config 结构体中的一些配置项来间接影响连接池的设置,例如设置连接的最大空闲时间等。

七、GORM 与 SpringBoot 的 mybatis等ORM 区别

感觉是mybatis的灵活性更好,能编写比较灵活的SQL语句;GORM需要SQL语句拼接