【Go】Go Gorm 详解

news2025/1/16 9:28:44

1. 概念

Gorm 官网:https://gorm.io/zh_CN/docs/

GormThe fantastic ORM library for Golang aims to be developer friendly,这是官网的介绍,简单来说 Gorm 就是一款高性能的 Golang ORM 库,便于开发人员提高效率

那么 ORM(Object Relation Mapping) 又是什么呢?在 Golang 语言中,Object指的就是 struct 结构体对象,Relation 就是数据库当中的关系,Mapping则表示两者具有映射关系,具体表现如下:

  • Go当中的结构体声明 <-> 数据库层面的表结构
  • Go当中的结构体实例 <-> 数据库层面的一条表记录

2. 数据库连接

2.1 安装依赖

想要在 Go 代码中使用 gorm 我们需要先引入对应的依赖:

  • gorm 库依赖:gorm.io/gorm
  • 特定数据库驱动依赖:gorm.io/driver/mysql

然后使用 go mod 包管理工具加载对应的依赖:

  1. go mod init first_gorm:初始化
  2. go mod tidy:加载依赖

然后就可以开始编写代码了!

2.2 连接数据库

在操作数据库之前,我们还需要与指定的数据库建立连接,此处以 MySQL数据库为例:

基本语法:db, err := gorm.Open(mysql.Open(dsn语句), &gorm.Config{})

  • 其中 dsn 语句为特定的连接格式,形式如下:user:pwd@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
package main

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

func main() {
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("数据库连接失败!", err)
	}
	fmt.Println(db)
}

程序运行结果:

控制台打印出 db 对象,说明我们已经成功与数据库建立连接(必须保证数据库中存在指定的数据库)

3. 数据库基本操作

3.1 创建表(表关系映射)

3.1.1 基本使用

我们可以使用 gorm 提供的 API 来创建指定的表,需要关注的是 结构体声明 <=> 数据库表结构,因此我们想要创建一个表结构实则只需要定义一个结构体类型

-- 创建user表 --
create table t_user (
  user_id bigint primary key auto_increment,
  user_name varchar(32) not null,
  user_pwd varchar(128) not null,
  user_phone varchar(32) unique
) 

使用上述 SQL 语句创建表的行为等价于在 Go 语言当中定义下列结构体对象:

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

创建表基本语法:err := db.AutoMigrate(&特定结构体{})

package main

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

// User 结构体声明
type User struct {
    UserId    int64  `gorm:"primaryKey;autoIncrement"`
    UserName  string `gorm:"not null;type:varchar(32)"`
    UserPwd   string `gorm:"not null;type:varchar(128)"`
    UserPhone string `gorm:"unique;type:varchar(32)"`
}

func main() {
    // 连接数据库
    var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        fmt.Println("数据库连接失败!", err)
    }
    err = db.AutoMigrate(&User{})
    if err != nil {
        fmt.Println("数据库表迁移失败!", err)
    }
}

程序运行结果:

3.1.2 自定义表名

我们发现定义结构体名称为 “User” 时会创建 “users” 的表名,但是如果我就希望叫做 “t_user” 应该怎么办呢?我们可以定义一个名为 TableName的方法接收器,格式如下:

func (*User) TableName() string {
	return "t_user"
}

删除原先的表后再次运行,可以发现此时表名称已经指定为t_user

3.2 新增记录

我们还可以使用 gorm 提供的 API 进行表记录的插入,这里我们需要关注** 结构体实例 <=> 表记录** 之间的映射关系,也就意味着我们可以通过创建一个结构体实例,实现插入一条记录的效果

3.2.1 单条数据插入

基本语法:db.Create(&结构体实例)

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("数据库连接失败!", err)
	}
	// 插入单条数据
	var user = User{UserName: "wjj", UserPwd: "123", UserPhone: "111"}
	db.Create(&user)
	// 再次打印user
	fmt.Println(user)
}

数据库表结果:

程序运行结果:

💡 提示:从中我们还可以发现,插入数据之后,还会将数据库表中记录回显到结构体实例当中!这也是为什么需要传递地址的原因!

3.2.2 批量插入数据

当我们需要批量插入多条数据的时候,循环调用 db.Create(&结构体实例)这个方法效率就太低了!因为数据库连接会话频繁创建销毁耗时比较高,更合适的方法就是进行批量插入

基本语法:db.Create(&结构体实例切片),仍旧是 Create 函数,但是参数我们可以传递结构体实例切片

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 批量插入多条数据
	var users = []User{
		{UserName: "th", UserPwd: "123", UserPhone: "222"},
		{UserName: "lhf", UserPwd: "123", UserPhone: "333"},
		{UserName: "zcy", UserPwd: "123", UserPhone: "444"},
	}
	db.Create(&users)
	// 打印结果
	fmt.Println(users)
}

数据库表结果:

程序运行结果:

3.3 查询记录

3.3.1 查询所有记录

基本语法:db.Find(&结构体实例切片)

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 查询全部记录
	var users []User
	db.Find(&users)
	// 打印结果
	fmt.Println(users)
}

程序运行结果:

3.3.2 按照条件查询

我们可以使用 Where 指定查询条件进行过滤

基本语法:db.Where("user_id > ?", 2).Find()表示想要查询 user_id > 2 的所有记录

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 按照条件查询
	var users []User
	db.Where("user_id > ?", 2).Find(&users)
	// 打印
	fmt.Println(users)
}

程序运行结果:

3.3.3 查询单条记录

查询单条记录有以下两种情况:

  • 查询第一条记录:db.First(&结构体实例)
  • 查询最后一条记录:db.Last(&结构体实例)
package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}
func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 查询第一条记录
	var firstUser User
	db.First(&firstUser)
	// 查询最后一条记录
	var lastUser User
	db.Last(&lastUser)
	fmt.Println(firstUser, lastUser)
}

程序运行结果:

3.3.4 查询记录总数

基本语法:db.Find(&结构体实例切片).Count(&整型变量)

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 查询总数
	var users []User
	var totalSize int64
	db.Find(&users).Count(&totalSize)
	fmt.Println("记录总数:", totalSize)
}

程序运行结果:

3.4 修改记录

3.4.1 按照默认主键修改

基本语法:db.Save(&结构体实例)会按照结构体实例当中的主键字段找到对应数据库记录进行修改

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 查询user_id为1的记录
	var stu User
	db.Where("user_id = ?", 1).Find(&stu)
	// 修改stu姓名为wjj1
	stu.UserName = "wjj1"
	// 修改(按照主键修改)
	db.Save(&stu)
}

程序运行结果:

3.4.2 修改指定字段

上述按照默认主键修改的方式修改了全部字段,如果我们只想修改特定单个字段可以使用以下方式:

基本语法:db.Model(&结构体实例).Where(条件).Update(字段, 修改值)

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 修改user_id为1的记录 user_name为wjj
	var stu User
	db.Model(&stu).Where("user_id = ?", 1).Update("user_name", "wjj")
}

程序运行结果:

3.4.3 修改多个字段

我们还可以指定多个字段进行修改

基本语法:db.Model(&结构体实例).Where(条件).updates(修改实例),其中修改实例可以是结构体也可以是map对象

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 修改user_id为1的记录 user_name为WJJ, user_pwd为"999"
	var stu User
	var fields = map[string]interface{}{"user_name": "WJJ", "user_pwd": "999"}
	db.Model(&stu).Where("user_id = ?", 1).Updates(fields)
}

程序运行结果:

3.5 删除记录

3.5.1 按照默认主键删除

基本语法:db.Delete(&结构体实例)会自动按照主键找到表中记录,然后删除

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 按照默认主键删除
	var user = User{UserId: 1}
	db.Delete(&user)
}

程序运行结果:

3.5.2 指定条件删除

我们想更加精细化的控制删除条件就需要借助 Where 函数:

基本语法:db.Where(条件).Delete(&结构体实例)

package main

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

// User 结构体声明
type User struct {
	UserId    int64  `gorm:"primaryKey;autoIncrement"`
	UserName  string `gorm:"not null;type:varchar(32)"`
	UserPwd   string `gorm:"not null;type:varchar(128)"`
	UserPhone string `gorm:"unique;type:varchar(32)"`
}

func (*User) TableName() string {
	return "t_user"
}

func main() {
	// 连接数据库
	var dsn = "root:QWEzxc123456@tcp(127.0.0.1:3306)/gorm_test"
	db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	// 按照条件删除
	db.Where("user_id = ?", 10).Delete(&User{})
}

程序运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277477.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机 AT24C02(I2C总线)

存储器 随机存储 RAM 只读存储 ROM AT24C02芯片 是一种可以实现掉电不丢失的存储器&#xff0c;可用于保存单片机运行时想要永久保存的数据信息 存储材质&#xff1a;E2PROM 通讯接口&#xff1a;I2C总线 容量&#xff1a;256字节 I2C总线 一种通用的数据总线 两根通信线…

再见IT!

再见IT 学了三年半前端&#xff0c;今天可能真的要和我最爱的前端说拜拜了&#xff01;没办法大局为重&#xff01; 在这个AI乱飞和短视频风口的时代&#xff0c;只能说当下学习任何一个技术远比2020年学习起来要简单的多。往后技术的发展无疑是飞速的&#xff0c;智能的&…

【开源免费】基于Vue和SpringBoot的人口老龄化社区服务与管理平台(附论文)

本文项目编号 T 140 &#xff0c;文末自助获取源码 \color{red}{T140&#xff0c;文末自助获取源码} T140&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

回归预测 | MATLAB实SVM支持向量机多输入单输出回归预测

效果一览 基本介绍 回归预测 | MATLAB实SVM支持向量机多输入单输出回归预测 …………训练集误差指标………… 1.均方差(MSE)&#xff1a;166116.6814 2.根均方差(RMSE)&#xff1a;407.5741 3.平均绝对误差&#xff08;MAE&#xff09;&#xff1a;302.5888 4.平均相对百分误…

系统学习算法:专题四 前缀和

题目一&#xff1a; 算法原理&#xff1a; 这道题是一维前缀和的模板题&#xff0c;通过这道题我们可以了解什么是前缀和 题意很简单&#xff0c;就是先输入数组个数和查询次数&#xff0c;然后将数组的值放进数组&#xff0c;每次查询给2个数&#xff0c;第一个是起点&#x…

智能科技与共情能力加持,哈曼重新定义驾乘体验

2025年1月6日&#xff0c;拉斯维加斯&#xff0c;2025年国际消费电子展——想象一下&#xff0c;当您步入一辆汽车&#xff0c;它不仅能响应您的指令&#xff0c;更能理解您的需求、适应您的偏好&#xff0c;并为您创造一个独特且专属的交互环境。作为汽车科技领域的知名企业和…

[java基础-集合篇]LinkedBlockingQueue源码解析

关联较强的上一篇&#xff1a;[java基础-集合篇]有界阻塞队列ArrayBlockingQueue源码解析-CSDN博客 总的来说。LinkedBlockingQueue 是一个基于链表节点的自定大小的线程安全的阻塞队列。遵循FIFO&#xff0c;结构上一端进一端出的单向队列。 源码注释 翻译 An optionally-boun…

从论文到实践:Stable Diffusion模型一键生成高质量AI绘画

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年12月24日10点02分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 AI绘画一键生成美图-变成画家 本地部…

业务幂等性技术架构体系之消息幂等深入剖析

在系统中当使用消息队列时&#xff0c;无论做哪种技术选型&#xff0c;有很多问题是无论如何也不能忽视的&#xff0c;如&#xff1a;消息必达、消息幂等等。本文以典型的RabbitMQ为例&#xff0c;讲解如何保证消息幂等的可实施解决方案&#xff0c;其他MQ选型均可参考。 一、…

【2024年华为OD机试】 (B卷,100分)- 跳房子I(Java JS PythonC/C++)

一、问题描述 题目描述 跳房子&#xff0c;也叫跳飞机&#xff0c;是一种世界性的儿童游戏。 游戏参与者需要分多个回合按顺序跳到第1格直到房子的最后一格。 跳房子的过程中&#xff0c;可以向前跳&#xff0c;也可以向后跳。 假设房子的总格数是count&#xff0c;小红每…

鸿蒙打包发布

HarmonyOS应用/元服务发布&#xff08;打包发布&#xff09; https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥&#xff1a;包含非对称加密中使用的公钥和私钥&#xff0c;存储在密钥库文件中&#xff0c;格式…

JAVA:在IDEA引入本地jar包的方法(不读取maven目录jar包)

问题&#xff1a; 有时maven使用的jar包版本是最新版&#xff0c;但项目需要的是旧版本&#xff0c;每次重新install会自动将mavan的jar包覆盖到项目的lib目录中&#xff0c;导致项目报错。 解决&#xff1a; 在IDEA中手动配置该jar包对应的目录。 点击菜单File->Projec…

Mac上安装Label Studio

在Mac上安装Anaconda并随后安装Label Studio&#xff0c;可以按照以下步骤进行&#xff1a; 1. 在Mac上安装Anaconda 首先&#xff0c;你需要从Anaconda的官方网站下载适用于Mac的安装程序。访问Anaconda官网&#xff0c;点击“Download Anaconda”按钮&#xff0c;选择适合M…

docker-compose和docker仓库

一、docker-compose 1.概述 docker-compose是一个自动编排工具&#xff0c;可以根据dockerfile自动化部署docker容器。 主要功能 配置定义 使用YAML文件&#xff08;通常命名为docker - compose.yml&#xff09;来描述应用程序的服务、网络和卷等配置。 容器编排 可以同时…

了解linux中的“of_property_read_u32()”

of_property_read_u32(node, "post-pwm-on-delay-ms",&data->post_pwm_on_delay); /*根据"post-pwm-on-delay-ms"&#xff0c;从属性中查找并读取一个32位整数*/ /*读到一个32位整数,保存到data->post_pwm_on_delay中*/ of_property_read_u32…

nodejs 037: 前端新手教程使用引导库 Intro.js

Intro.js简介 Intro.js 是一个流行的引导库&#xff0c;用于提供步进式的新手教程。它可以帮助你创建用户引导&#xff0c;展示一些步骤和提示&#xff0c;逐步引导用户了解应用程序的功能。 安装方法&#xff1a; npm install intro.js使用方法&#xff1a; import introJ…

Vue篇-07

Vue UI组件库 一、移动端常用的UI组件库 1.1、Vant 1.2、Cube UI 1.3、Mint UI 二、PC端常用的UI组件库 2.1、Element UI Element - The worlds most popular Vue UI framework 安装&#xff1a; 按需引入&#xff1a; 135_尚硅谷Vue技术_element-ui按需引入_哔哩哔哩_b…

适配器模式案例

如果在这样的结构中 我们在Controller中注入&#xff0c;但我们后续需要修改Oss时&#xff0c;比如从minioService改成AliyunService时&#xff0c;需要改动的代码很多。于是我们抽象出一个FileService&#xff0c;让controller只跟fileservice耦合&#xff0c;这样我没只需要在…

鸿蒙UI开发——键盘弹出避让模式设置

1、概 述 我们在鸿蒙开发时&#xff0c;不免会遇到用户输入场景&#xff0c;当用户准备输入时&#xff0c;会涉及到输入法的弹出&#xff0c;我们的界面针对输入法的弹出有两种避让模式&#xff1a;上抬模式、压缩模式。 下面针对输入法的两种避让模式的设置做简单介绍。 2、…

Vue2+OpenLayers实现折线绘制功能(提供Gitee源码)

目录 一、案例截图 二、安装OpenLayers库 三、代码实现 3.1、初始变量 3.2、画一条折线 3.3、完整代码 四、Gitee源码 一、案例截图 二、安装OpenLayers库 npm install ol 三、代码实现 3.1、初始变量 关键代码&#xff1a; data() {return {map:null,// 定义路径坐…