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.ModelName   stringAge    uintActive bool
}

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

数据库连接和配置

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

package mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 mainimport ("fmt""gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 Userresult := db.First(&user, 1) // 查询ID为1的用户// 检查错误if result.Error != nil {panic(result.Error)}fmt.Println(user.Name)
}
更新(U)

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

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

package mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 Userdb.Model(&user).Update("Name", "Jin")
}
删除(D)

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

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

package mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 Userdb.Delete(&user, 1) // 删除 ID 为1的用户
}
关联处理

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

package mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelCreditCards []CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID 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 Userdb.Preload("CreditCards").Find(&user)
}

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

type User struct {gorm.ModelName   stringAge    uintActive bool
}type Profile struct {gorm.ModelUser User
}// 一对多(Has Many)
type Post struct {gorm.ModelContent stringUser    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 mainimport ("gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelCreditCards []CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID 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 Uservar creditCard CreditCard// 开启一个事务tx := db.Begin()// 在事务中进行一系列操作tx.Create(&user)tx.Create(&creditCard)// 如果操作成功,则提交事务tx.Commit()// 如果中间产生了错误,您可以回滚这个事务tx.Rollback()
}

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

钩子(Hooks)

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

package mainimport ("fmt""gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm"
)type User struct {gorm.ModelName   stringAge    uintActive 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 Userdb.Create(&user)db.Save(&user)
}

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

type User struct {gorm.ModelName 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 mainimport ("fmt""gorm.io/driver/mysql" // 修改为相应的数据库驱动"gorm.io/gorm""gorm.io/gorm/logger""log""os""time"
)type User struct {gorm.ModelName   stringAge    uintActive 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)

 

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

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

相关文章

在Ubuntu系统中使用Systemctl添加启动项的详细指南

在Ubuntu系统中使用Systemctl添加启动项的详细指南 在Ubuntu系统中,systemctl 是管理systemd服务的主要工具。通过它,你可以添加、启动、停止、重启、启用和禁用服务。 什么是Systemctl? systemctl 是一个用于管理systemd系统和服务管理器…

OpenHarmony迎来首个互联网技术统一标准,鸿蒙OS生态走向如何?

开源三年半,OpenHarmony(以下简称“开源鸿蒙”)迎来了新进展。在5月25日召开的「OpenHarmony开发者大会」上,鸿蒙官宣了开源鸿蒙设备统一互联技术标准。 一直以来,各行业品牌操作系统相互独立、难以协同,成为其互联互通的痛点。为进一步解决…

Unity SetParent第二个参数worldPositionStays的意义

初学Unity的小知识: 改变对象的父级有三种调用方式,如下: transMe.SetParent(transParent,true); transMe.SetParent(transParent,false); transMe.parent transParent;具体有什么区别呢,这里写一个测试例子来详细说明&#xff…

数据驱动的UI艺术:智能设计的视觉盛宴

数据驱动的UI艺术:智能设计的视觉盛宴 引言 在当今这个数据泛滥的时代,大数据不仅仅是一种技术手段,它更是一种艺术形式。当大数据遇上UI设计,两者的结合便催生了一种全新的艺术形式——数据驱动的UI艺术。本文将探讨如何将数据…

STM32建立工程问题汇总

老版本MDK,例如MDK4 工程内容如下: User文件夹中存放main.c文件,用户中断服务函数(stm32f1xx.it.c),用户配置文件(stm32f1xx_hal_conf.h)等用户程序文件,或者mdk启动程序…

5,串口编程---实现简单的用串口发送接收数据

单片机通过串口向PC机发送数据 PC机通过串口接收单片机发过来的数据 1.UART和USART的区别: USART支持同步通信方式,可以通过外部时钟信号进行同步传输,而UART仅支持异步通信方式 本开发板STM32F103ZET6有5个串口,用串口1作调试串口,因为串…

关于我转生从零开始学C++这件事:升级Lv.25

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载,请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤ OK了老铁们,又是一个周末,大伟又来继续给大家更新我们的C的内容了。那么根据上一篇博…

php之web开发

目标 实现一款具有常用大部分功能的WEB应用&#xff0c;并初步了解WEB漏洞原理 登录功能&#xff1a; 1、基于前端的登录功能 <!DOCTYPE html> <html> <head> <title>简单登录功能</title> </head> <meta charset"UTF-8"…

【Python】 Python中的“命名元组”:简单而强大的数据结构

基本原理 在Python中&#xff0c;namedtuple是tuple的一个子类&#xff0c;它允许我们为元组的每个位置指定一个名字。这种数据结构非常适合用于需要固定字段和值的场景&#xff0c;例如数据库查询的结果或配置文件中的设置。 namedtuple提供了一种方便的方式来访问元组中的元…

海外盲盒系统APP开发,盲盒出海热潮下的蓝海

近几年&#xff0c;我国潮玩出海成为了一个的大风口。根据数据显示&#xff0c;今年全球潮玩规模将达到400多亿美元&#xff0c;市场发展空间巨大。海外庞大的市场对于我国盲盒出海是一个较大的优势。在当下互联网的快速发展下&#xff0c;海外盲盒APP商城成为了盲盒企业出海的…

开源VS闭源:谁将引领AI大模型的新时代?

一、引言 随着人工智能技术的飞速发展&#xff0c;AI大模型已成为推动这一浪潮的核心动力。在AI大模型的发展过程中&#xff0c;开源与闭源两种不同的发展路径一直备受关注。本文将深入探讨这两种路径的优劣势&#xff0c;分析它们对AI大模型发展的影响&#xff0c;并预测谁将…

ctfshow web入门 黑盒测试

web380 这里文章看的我好有感触 但是影响做题 扫描一下 访问flag.php啥也没有再访问page.php page.php?idflagweb381 扫出来page.php但是没啥用哇&#xff0c;查看源代码 这些文件挨个试发现啥也没&#xff0c;最后仔细对比发现其实都是layui&#xff0c;然后尝试着访问…

《架演》共创者第一次线上沟通会议总结

《架演》共创者第一次线上沟通——启动会 会议主题&#xff1a;《架演》共创启动会议会议时间&#xff1a;2024年5月28日&#xff0c;20:00 - 21:00会议地点&#xff1a;腾讯会议主持人&#xff1a;寒山参会人员&#xff1a; 夏军、mirror、刘哥、悟缺席人员&#xff1a;可心、…

Cocos Creator 安卓环境配置

系统&#xff1a;Win10&#xff0c;引擎版本&#xff1a;CocosCreator3.8.2&#xff0c; 时间&#xff1a;2024.05.23 安装 Java SDK(JDK)下载地址 注意&#xff1a;Java版本对应的Gradle: 详见表 Table 1. Java Compatibility 此处选择 Java 21 对应 Gradle 8.5 配置Java系统…

2024.05.22学习记录

1、面经复习&#xff1a; Vue组件通讯、vuex、js严格模式、options请求、vue3 Setup 语法糖、React hook 2、代码随想录刷题&#xff1a;动态规划 3、rosebush组件库 完成Alert和Alert测试 Menu组件初步开发

RocketMQ 主从复制原理深度解析

提到主从复制&#xff0c;我们可能立马会联想到 MySQL 的主从复制。 MySQL 主从复制是 MySQL 高可用机制之一&#xff0c;数据可以从数据库服务器主节点复制到一个或多个从节点。 这篇文章&#xff0c;我们聊聊 RocketMQ 的主从复制&#xff0c;希望你读完之后&#xff0c;能…

文献解读-群体基因组第一期|《对BMI的影响:探究BMI的基因型-环境效应》

关键词&#xff1a;应用遗传流行病学&#xff1b;群体测序&#xff1b;群体基因组&#xff1b;基因组变异检测&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;The Impact of ACEs on BMI: An Investigation of the Genotype-Environment Effects of BMI标…

knex与sequelize 以及断点工具使用

knex 使用 SQL Query Builder for Javascript | Knex.js 首先下载 npm install knex 使用 const knex require(knex)({client: mysql,connection: {host: localhost, // 地址user: root, // 账号password: 123456, // 密码database: user // 数据库}});/*** kn…

React-组件基础使用

组件是什么 概念&#xff1a;一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观&#xff0c;组件之间可以互相嵌套&#xff0c;也可以复用多次 组件化开发可以让开发者像搭积木一样构建一个完整的庞大的应用 React组件 在React中&#xff0c;一个组件就是首…

云动态摘要 2024-05-24

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [免费试用]大模型知识引擎体验招募 腾讯云 2024-05-21 大模型知识引擎产品全新上线&#xff0c;为回馈新老客户&#xff0c;50万token免费送&#xff0c;开通服务即领取&#xff01; 云服…