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系统和服务管理器…

std::vector<数据类型>(大小),较常用的相关方法总结

一、初始化 我的理解是vector就相当于数组&#xff0c;可以是整型数组、字符串数组等&#xff0c;其中存放什么数组取决于<数据类型> std::vector<int> a; // 整型数组std::vector<string> b; // 字符串数组a {1,2,3,4,5,6};std::cerr << a.size() &…

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

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

顺序表以及实现(结构篇)

顺序表是一种线性表的存储结构&#xff0c;它使用一组地址连续的存储单元依次存储线性表的数据元素。在顺序表中&#xff0c;逻辑上相邻的元素在物理存储上也相邻&#xff0c;通常采用数组来实现这种存储方式。 前言&#xff1a; 顺序表格的特点&#xff1a; 随机访问&#x…

【MySQL精通之路】SQL语句(7)-数据库管理语句(3)-表维护语句

目录 1.ANALYZE TABLE语句 1.1 输出 1.2 KEY分布分析 1.3 直方图统计分析 2.CHECK TABLE语句 2.1 输出 2.2 检查版本兼容性 2.3 检查数据一致性 2.4 InnoDB表的CHECK TABLE的使用说明 2.5 MyISAM表的CHECK TABLE使用说明 3.CHECKSUM TABLE语句 3.1 性能注意事项 4…

Unity SetParent第二个参数worldPositionStays的意义

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

LLaMA-Factory 微调训练

LLaMA-Factory 微调训练 该框架功能&#xff0c;标注-微调-导出-合并-部署&#xff0c;一整条流程都有&#xff0c;而且训练时消耗的gpu算力也会小一些 一&#xff0c;安装&#xff08;推荐在linux中训练&#xff0c;win可以用wsldocker&#xff09; git clone https://githu…

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

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

STM32建立工程问题汇总

老版本MDK&#xff0c;例如MDK4 工程内容如下&#xff1a; User文件夹中存放main.c文件&#xff0c;用户中断服务函数&#xff08;stm32f1xx.it.c&#xff09;&#xff0c;用户配置文件&#xff08;stm32f1xx_hal_conf.h&#xff09;等用户程序文件&#xff0c;或者mdk启动程序…

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

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

攻击渗透思考题

1. windows登录的明文密码&#xff0c;存储过程是怎么样的&#xff0c;密文存在哪个文件下&#xff0c;该文件是否可以打开&#xff0c;并且查看到密文 在Windows操作系统中&#xff0c;登录时输入的明文密码不会以明文形式存储在系统中。相反&#xff0c;Windows使用一种称为“…

数据库mysql

一、mysql常用语句 登录MySQLmysql -u root -p列出所有数据库SHOW DATABASES;创建一个新数据库CREATE DATABASE test;删除一个数据库DROP DATABASE test;对一个数据库进行操作时USE test;列出当前数据库的所有表SHOW TABLES;要查看一个表的结构DESC students;创建表CREATE TAB…

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

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载&#xff0c;请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主&#xff0c;代码兴国&#xff01;❤❤❤ OK了老铁们&#xff0c;又是一个周末&#xff0c;大伟又来继续给大家更新我们的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商城成为了盲盒企业出海的…

【MySQL精通之路】优化(1)-查询优化(6)-索引条件下推

1.介绍 Index Condition Pushdown&#xff08;ICP&#xff09;是针对MySQL使用索引从表中检索行的情况进行的优化。 在没有ICP的情况下&#xff0c;存储引擎遍历索引以定位基表中的行&#xff0c;并将它们返回给MySQL服务器&#xff0c;MySQL服务器会评估这些行的WHERE条件。 启…

开源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;可心、…