Go GORM介绍

GORM 是一个功能强大的 Go 语言 ORM(对象关系映射)库,它提供了一种方便的方式来与 SQL 数据库进行交互,而不需要编写大量的 SQL 代码。

GORM的关键特性

  • 全功能的ORM:支持几乎所有的ORM功能,包括模型定义、基本的CRUD操作、复杂查询、关联处理等。

  • 关联支持:非常灵活的关联(has one, has many, belongs to, many to many, polymorphism, single-table inheritance)功能。

  • 钩子(Hooks):支持在create/save/update/delete/find操作前后进行自定义处理。

  • 预加载(Eager Loading):使用Preload, Joins等方式预加载关联数据。

  • 事务处理:支持事务、嵌套事务、保存点以及回滚到保存点。

  • 上下文支持: 支持上下文管理、准备语句模式、DryRun模式。

  • 批量操作: 支持批量插入、分批次查询、通过Map进行查找/创建、使用SQL Expr和Context Valuer进行CRUD。

  • SQL构建器: 支持Upsert、锁定、优化器/索引/注释提示、命名参数以及子查询。

  • 复合主键、索引、约束:对于复合主键、索引和约束也有很好的支持。

  • 自动迁移(Auto Migrations): 支持自动数据库迁移。

  • 日志: 支持日志记录功能。

  • 插件API:提供可扩展、灵活的插件API, 如数据库解析器(支持多数据库、读写分离)/ Prometheus监控。

  • 测试完备:每一个功能都伴随着对应的测试用例。

GORM的基本使用 

安装

go get -u gorm.io/gorm

模型定义

在 GORM 中,模型通常由 Go 结构体表示,每一个模型对应数据库中的一个表。

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

在上面的代码中,gorm.Model 是一个包含了 ID, CreatedAt, UpdatedAt, DeletedAt 字段的基础模型。我们在此基础上添加了自定义字段(Name, Age, Active)。

数据库连接和配置

假设您已经有一个运行中的关系型数据库(比如 PostgreSQL、MySQL 等),您可以使用以下方式连接到数据库:

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})
}

连接数据库是使用数据库之前必须要做的步骤,上述代码展示了如何使用GORM连接到MySQL数据库。

CRUD 操作

// 创建
user := User{Name: "Alice", Age: 20}
db.Create(&user)

// 查询
var users []User
db.Find(&users)

// 更新
db.Model(&user).Update("age", 21)

// 删除
db.Delete(&user)
创建(C)

对数据库进行操作的第一步通常是向数据库中添加新记录。GORM使这个过程变得非常简单,示例如下:

上面的代码创建了一条新的用户记录。 

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})

	user := User{Name: "Jinzhu", Age: 18, Active: true}
	result := db.Create(&user) // 通过数据模型创建记录

	// 检查错误
	if result.Error != nil {
		panic(result.Error)
	}
}
查询(R)

读取或查询数据库中现有数据是 ORM 最常用的功能之一。GORM 提供了灵活的查询方法。以下是查询单个记录的示例:

上述代码从数据库中查询ID为1的用户记录,并打印出用户名。 

package main

import (
	"fmt"
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})

	var user User
	result := db.First(&user, 1) // 查询ID为1的用户

	// 检查错误
	if result.Error != nil {
		panic(result.Error)
	}

	fmt.Println(user.Name)
}
更新(U)

更新现有记录是另一个常见的数据库操作。GORM 提供了多种更新方法,以下是如何更新一条记录的示例:

此代码将用户名更新为"Jin" 

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})

	var user User
	db.Model(&user).Update("Name", "Jin")
}
删除(D)

当需要从数据库中移除记录时,可以使用GORM的删除功能。在GORM中,删除可以是软删除(只更新DeletedAt字段,数据实际还在)或硬删除(实际从数据库中移除数据)。以下是删除一个用户的示例:

 上面的代码将从数据库中删除ID为1的用户。

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})

	var user User
	db.Delete(&user, 1) // 删除 ID 为1的用户
}
关联处理

GORM提供了强大的关联处理能力,它支持一对一、一对多、多对多等关系。下面是一个一对多关系的例子,其中User有多个CreditCard

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	CreditCards []CreditCard
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID uint
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{}, &CreditCard{})

	var user User
	db.Preload("CreditCards").Find(&user)
}

上述代码中,Preload 函数预加载了用户的所有信用卡记录。这就是使用GORM处理关联的一个例子。

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

type Profile struct {
    gorm.Model
    User User
}

// 一对多(Has Many)
type Post struct {
    gorm.Model
    Content string
    User    User
}

// 设置和创建关联
user := User{Name: "Alice"}
db.Create(&user)
db.Model(&user).Association("Posts").Create(&Post{Content: "First post"})

 以上代码创建User同时创建Post并关联User

GORM的高级使用

除了基本的CRUD操作,GORM还提供了高级功能,包括但不限于事务、Hooks、SQL构建器、日志记录等。这些功能可以帮助处理更复杂的场景,并使数据处理更加灵活和可控。

事务处理

tx := db.Begin()
defer func() {
    if r := recover(); r != nil {
        tx.Rollback()
    }
}()

// 执行一些操作...
tx.Commit()

在复杂的操作中,您可能需要按照事务来执行一系列数据库操作,确保数据的一致性和完整性。GORM 使得处理事务变得简单。以下是一个使用事务的例子:

package main

import (
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	CreditCards []CreditCard
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID uint
}

func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{}, &CreditCard{})

	var user User
	var creditCard CreditCard
	// 开启一个事务
	tx := db.Begin()

	// 在事务中进行一系列操作
	tx.Create(&user)
	tx.Create(&creditCard)

	// 如果操作成功,则提交事务
	tx.Commit()

	// 如果中间产生了错误,您可以回滚这个事务
	tx.Rollback()
}

事务功能是确保数据安全性非常重要的一个功能。

钩子(Hooks)

GORM 允许您定义模型的钩子,例如在保存记录之前后自动执行特定功能。以下是定义BeforeSaveAfterCreate钩子的示例:

package main

import (
	"fmt"
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func (u *User) BeforeSave(tx *gorm.DB) (err error) {
	fmt.Println("每次Save操作之前,将打印相应的消息。")
	return
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
	fmt.Println("每次Create操作之后,将打印相应的消息。")
	return
}
func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 接下来可以使用 `db` 句柄进行数据库操作
	// 比如迁移模式
	db.AutoMigrate(&User{})

	var user User
	db.Create(&user)
	db.Save(&user)
}

在以上代码中,每次Save操作之前和Create操作之后,将打印相应的消息。

type User struct {
    gorm.Model
    Name string
}

// 钩子示例:在创建之前清空名字字段
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
    u.Name = strings.ToUpper(u.Name)
    return
}

// 使用
user := User{Name: "alice"}
db.Create(&user) // 用户名将被转换为 ALICE

SQL构建器和日志记录

GORM 的SQL构建器非常强大,提供了灵活的查询方式。同时,GORM 的日志记录功能使得调试和检查变得简单:

db.Where("name = ?", "jinzhu").First(&user)

上述代码展示了如何构造一个普通的查询,并且 GORM 会记录此次查询的日志输出。 

调整日志级别

GORM 允许你设置不同的日志级别,以控制日志输出的详细程度。日志级别包括:

  • logger.Silent:不输出任何日志信息。
  • logger.Error:只输出错误信息。
  • logger.Warn:输出错误和警告信息。
  • logger.Info:输出错误、警告和一般信息,包括慢查询。
  • logger.Debug:输出所有 SQL 语句和执行时间。 
慢查询日志 

SlowThreshold 配置项允许你设置慢查询的阈值。在这个阈值以上的查询将被视为慢查询,并在日志中特别标记出来。 

彩色日志

Colorful 配置项允许你开启彩色日志输出,这可以使得日志输出更加易于阅读。

package main

import (
	"fmt"
	"gorm.io/driver/mysql" // 修改为相应的数据库驱动
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

type User struct {
	gorm.Model
	Name   string
	Age    uint
	Active bool
}

func (u *User) BeforeSave(tx *gorm.DB) (err error) {
	fmt.Println("每次Save操作之前,将打印相应的消息。")
	return
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
	fmt.Println("每次Create操作之后,将打印相应的消息。")
	return
}
func main() {
	dsn := "username:password@protocol(address)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	_, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.New(
			log.New(os.Stdout, "\r\n", log.LstdFlags), // 日志输出
			logger.Config{
				SlowThreshold: 100 * time.Millisecond, // 慢查询阈值,任何执行时间超过 100 毫秒的查询都会被记录为慢查询
				LogLevel:      logger.Info,            // 日志级别
				Colorful:      true,                   // 彩色日志
			},
		),
	})
	if err != nil {
		panic("failed to connect database")
	}
}

慢查询日志(Slow Query Log)是数据库管理系统中的一种日志记录功能,用于记录执行时间超过预设阈值的 SQL 查询。这个特性在 MySQL、PostgreSQL 等数据库中都有支持,并且 GORM 也提供了相应的配置来帮助开发者捕捉和记录这些慢查询。

理解慢查询日志的几个关键点:
  1. 阈值(Threshold)

    • 阈值是指查询执行时间的上限,超过这个时间的查询将被认为是“慢查询”。
    • 在 GORM 中,可以通过 logger.Config 的 SlowThreshold 字段设置这个阈值。
  2. 日志记录

    • 慢查询日志记录了慢查询的详细信息,包括查询的 SQL 语句、执行时间、执行时的时间戳等。
    • 这些信息对于分析性能瓶颈和优化数据库查询非常有用。
  3. 性能分析

    • 通过分析慢查询日志,开发者可以识别出影响数据库性能的查询语句。
    • 可以进一步对这些查询进行优化,比如通过添加索引、改写查询逻辑或调整数据库结构。
  4. 实时监控

    • 在一些情况下,慢查询日志可以配置为实时输出,帮助开发者及时发现并处理性能问题。
  5. 资源消耗

    • 记录慢查询日志会消耗一定的系统资源,因为它需要额外的 I/O 操作来记录日志信息。
    • 因此,通常在开发环境或性能测试时开启慢查询日志,而在生产环境中根据需要谨慎使用。
  6. 配置和使用

    • 在 GORM 中,慢查询日志的记录可以通过配置 logger.Config 来开启。
    • 开启慢查询日志后,GORM 会在日志输出中标记出执行时间超过 SlowThreshold 的查询。

预加载

预加载可以减少数据库查询次数。

db.Preload("Profile").Find(&users)
var users []User
db.Preload("Profile").Find(&users, "age > ?", 18) // 预加载 Profile 关联并查询年龄大于 18 的用户

 上下文支持 

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// 使用上下文执行查询
db.WithContext(ctx).Find(&users)

 批量操作

users := []User{{Name: "Alice"}, {Name: "Bob"}}
db.CreateInBatches(users, 10) // 批量创建用户

SQL 构建器

db.Table("users").Select("name, age").Where("age >= ?", 20).Scan(&users)

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

揭秘C++ String容器:字符串操作的艺术

目录 ​编辑 引言 一、初识std::string:构造与初始化 二、字符串的操纵艺术:拼接、查找与替换 三、访问与遍历:字符的细腻触感 四、大小与容量:动态调整的智慧 五、进阶功能:探索更多可能 结语 引言 在C标准库…

vue3+electron+typescript 项目安装、打包、多平台踩坑记录

环境说明 这里的测试如果没有其他特别说明的,就是在win10/i7环境,64位 创建项目 vite官方是直接支持创建electron项目的,所以,这里就简单很多了。我们已经不需要向开始那样自己去慢慢搭建 yarn create vite这里使用yarn创建&a…

特殊变量笔记3

输入一个错误命令, 在输出$? 特殊变量:$$ 语法 $$含义 用于获取当前Shell环境的进程ID号 演示 查看当前Shell环境进程编号 ps -aux|grep bash输出 $$ 显示当前shell环境进程编号 小结 常用的特殊符号变量如下 特殊变量含义$n获取输入参数的$0, 获取当前She…

将3D检测的box框投影到BEV图片上

前言 点云数据作为一种丰富的三维空间信息表达方式,通常用于自动驾驶、机器人导航和三维建模等领域。然而,点云数据的直观性不如二维图像,这限制了它在一些需要快速视觉反馈的应用场景中的使用。本文将探讨如何将点云数据转换为二维图像&…

Thymeleaf 搭建家居网首页

文章目录 1.引入Thymeleaf sunliving-commodity模块1.在resources目录下引入Thymeleaf 所需资源2.pom.xml引入Thymeleaf依赖3.application.yml 关闭缓存,使页面实时刷新4.在application-prod.yml开启缓存5.编写com/sun/sunliving/commodity/web/IndexController.jav…

OpenUI 可视化 AI:打造令人惊艳的前端设计!

https://openui.fly.dev/ai/new 可视化UI的新时代:通过人工智能生成前端代码 许久未更新, 前端时间在逛github,发现一个挺有的意思项目,通过口语化方式生成前端UI页面,能够直观的看到效果,下面来给大家演示下 在现代…

idea2023的git从dev分支合并到主分支master

1.本地项目切换到主分支master 右键项目-git-Branches 依次点击项目-Remote-Origin-master-CheckOut 现在你的idea中的这个项目就是远程master分支的代码了。 2.合并dev分支到master 右击项目-git-Merge 选择origin-dev 点击Merge按钮,此时只是合并到本地的maste…

Weblogic XML反序列化漏洞 [CVE-2017-10271]

漏洞环境搭建请参考 http://t.csdnimg.cn/i11e2 漏洞原理 Weblogic的wls security组件对外提供webservice服务,wls security组件使用了xmldecoder来解析用户传入的xml数据,如果用户进行xml恶意数据的构造,即可触发反序列化漏洞 漏洞版本 O…

【MySQL】聊聊count的相关操作

在平时的操作中,经常使用count进行操作,计算统计的数据。那么具体的原理是如何的?为什么有时候执行count很慢。 count的实现方式 select count(*) from student;对于MyISAM引擎来说,会把一个表的总行数存储在磁盘上,…

Dbs封装_连接池

1.Dbs封装 每一个数据库都对应着一个dao 每个dao势必存在公共部分 我们需要将公共部分抽取出来 封装成一个工具类 保留个性化代码即可 我们的工具类一般命名为xxxs 比如Strings 就是字符串相关的工具类 而工具类 我们将其放置于util包中我们以是否有<T>区分泛型方法和非泛…

pycharm连接阿里云服务器过程记录

因为不想用自己的电脑安装anaconda环境,所以去查了一下怎么用服务器跑代码,试着用pycharm连接阿里云服务器,参考了很多博客,自己简单配置了一下,记录一下目前完成的流程. 主要是:阿里云服务器的远程登录和安装anaconda,以及怎么用pycharm连接阿里云服务器上的解释器. 小白刚开始…

Java进阶学习笔记27——StringBuilder、StringBuffer

StringBuilder&#xff1a; StringBuilder代表可变字符串对象&#xff0c;相当于一个容器&#xff0c;它里面装的字符串是可以改变的&#xff0c;就是用来操作字符串的。 好处&#xff1a; StringBuilder比String更适合做字符串的修改操作&#xff0c;效率会更高&#xff0c;…

【FPGA】Verilog:奇校验位生成器的实现(Odd Parity bit generator)

解释奇数奇偶校验位生成器和检查器的仿真结果及过程。 真值表和卡洛图: Odd Parity Bit Generator A B C

利用element实现简单右键

利用element-plus中的el-menu实现简单右键 实现如下 <template><main class"mainClass" contextmenu"showMenu($event)"> </main><el-menu:default-active"1"class"el-menu-demo"mode"vertical":col…

GitHub怎么修改个人资料名称name和用户名username

文档 GitHub•GitHub文档•Get started•帐户和个人资料•配置文件•自定义个人资料•个性化设置https://docs.github.com/zh/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile GitHub•GitHub文档•G…

从XPS迁移到IP Integrator

从XPS迁移到IP Integrator 概述 AMD Vivado™设计套件IP集成器可让您将包含AMD的设计缝合在一起 IP或您的自定义IP在相对较短的时间内&#xff0c;在GUI环境中工作。 就像在Xilinx Platform Studio中一样&#xff0c;您可以快速创建嵌入式处理器设计&#xff08;使用&#xff0…

【STM32】新建工程(江科大)

文章目录 STM32的开发方式库函数文件夹一、新建一个基于标准库的工程1.建立一个存放工程的文件夹2.打开Keil5 二、通过配置寄存器来完成点灯1.配置RCC寄存器2.配置PC13口&#xff08;1&#xff09;配置PC13口的模式&#xff08;2&#xff09;给PC13口输出数据 三、为寄存器添加…

5.26牛客循环结构

1002. 难点&#xff1a; 两层循环条件设置 思路 可以设置三个变量 代码 1003 思路&#xff1a; 与星号双塔差不多&#xff0c;在此基础上加大一点难度 每日练题5.23 &#xff08;EOF用法&#xff09;-CSDN博客 代码 1004 代码

微信小程序如何跳转微信公众号

1. 微信小程序如何跳转微信公众号 1.2. 微信公众号配置 登录微信公众号&#xff0c;点击【小程序管理】&#xff1a;   点击【添加】&#xff1a;   点击【关联小程序】&#xff1a;   输入小程序进行关联&#xff1a; 1.2. 微信小程序配置 登录微信小程序&#xf…

物联网应用开发--传感器数据上传新大陆云平台(STM32+SHT20温湿度+ESP8266+TCP)

实现目标 1、掌握新大陆云平台传感器的创建 2、熟悉STM32 HAL与ESP8266模块之间的通信 3、具体实现目标&#xff1a;&#xff08;1&#xff09;创建2个传感器&#xff1a;温度传感器&#xff0c;湿度传感器;&#xff08;2&#xff09;上传开发板上的SHT20温湿度传感器数据至…