24 go语言(golang) - gorm框架安装及使用案例详解

一、简介

官方文档

GORM是一个用于Go语言的ORM(对象关系映射)库,它简化了与数据库交互的过程。GORM支持多种数据库,包括MySQL、PostgreSQL、SQLite和SQL Server等。

1.1 关键特性

  1. 自动迁移:GORM可以根据结构体自动创建或更新数据库表。
  2. CRUD操作:提供简单的方法进行增删改查操作。
  3. 关联关系:支持一对一、一对多、多对多等复杂的关联关系。
  4. 事务支持:可以方便地在事务中执行多个操作。
  5. 钩子函数:在创建、更新、删除之前或之后执行自定义逻辑。

二、基础用法

2.1 安装

1、要使用GORM,首先需要安装它

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

2、为了方便测试,我这里本地使用docker启动一个mysql服务,并创建一个库,确保可用

2.2 初始化连接

package mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/schema""testing"
)var db = getMysqlConnect()func getMysqlConnect() *gorm.DB {url := "root:123456@tcp(127.0.0.1:3306)/local?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(url), &gorm.Config{})if err != nil {panic("failed to connect database")}return db
}

2.3 定义模型并自动迁移

定义一个模型,并让GORM为其创建对应的数据表

type DwdUserInfo struct {ID       uint   `gorm:"primaryKey"`Username string `gorm:"size:100"`
}func Test1(t *testing.T) {// 自动迁移模式,会创建表结构,如果不存在的话。err := db.AutoMigrate(&DwdUserInfo{}) // 创建的表明是dwd_user_infosif err != nil {fmt.Println(err.Error())return}
}

如果不想要它建表时加个s,可以自定义表名,或者关掉这个配置开关

	// 通过设置 SingularTable: true,GORM 将使用单数形式作为默认的表名。db, err := gorm.Open(mysql.Open(url), &gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true,},})// 或者实现 TableName() 方法来覆盖默认实现
func (user *DwdUserInfo) TableName() string {return "user_info"
}

2.4 CRUD 操作

func Test2(t *testing.T) {// 插入数据db.Create(DwdUserInfo{1, "小明"})db.Create(DwdUserInfo{123, "小明1"})db.Create(DwdUserInfo{999, "小明2"})// 查询数据var user1 DwdUserInfodb.First(&user1) // 查询第一条记录fmt.Println(user1)var user2 DwdUserInfodb.First(&user2, 999) // 根据主键查询第一条记录fmt.Println(user2)var userList []DwdUserInfodb.Find(&userList) // 查询所有用户fmt.Println(userList)// 条件查询db.Where("username = ?", "小明2").Find(&userList)fmt.Println(userList)// 更新数据db.Model(&user1).Update("username", "修改后的名字")db.Model(&user1).Updates(DwdUserInfo{Username: "修改后的名字2"}) // 使用struct更新多个字段,只会更新非零值字段// 删除数据db.Delete(&user1) // 读取结构体中的id去删除var user3 DwdUserInfodb.Delete(&user3, 999) // 删除id为999的数据
}

三、模型定义

3.1 字段标签

  • gorm:"primaryKey":指定主键。
  • gorm:"unique":指定唯一字段。
  • gorm:"uniqueIndex":为该字段创建唯一索引。
  • gorm:"not null":指定非空字段。
  • gorm:"default:xxx":设置默认值。
  • gorm:"column:xxx":指定数据库中对应的列名。
  • gorm:"index":为该字段创建索引。
  • gorm:"autoIncrement":指定字段为自增字段(适用于整数类型的字段)。
  • gorm:"size:xxx":指定字段的大小,主要用于字符串或数组类型的字段。
type User struct {ID          uint           `gorm:"primaryKey;autoIncrement"`Name        string         `gorm:"size:100;uniqueIndex:idx_name_and_code"`Code        string         `gorm:"size:100;uniqueIndex:idx_name_and_code"`Email       string         `gorm:"type:varchar(100);unique"` // type直接指定类型BirthDate   time.Time      `gorm:"index"`IsValid     bool           `gorm:"default:true"`CreateTime  time.Time      `gorm:"autoCreateTime"` // 自动设置创建时间UpdateTime  time.Time      `gorm:"autoUpdateTime"` // 自动设置更新时间DeletedAt   gorm.DeletedAt `gorm:"index"`          // 软删除字段TestNotNull string         `gorm:"not null"`TestColumn  string         `gorm:"column:xxx"`
}func Test3(t *testing.T) {err := db.AutoMigrate(&User{})if err != nil {fmt.Println(err.Error())}
}

执行后对应mysql自动创建的表:

CREATE TABLE `user` (`id` bigint unsigned NOT NULL AUTO_INCREMENT,`name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,`code` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,`email` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,`birth_date` datetime(3) DEFAULT NULL,`is_valid` tinyint(1) DEFAULT '1',`create_time` datetime(3) DEFAULT NULL,`update_time` datetime(3) DEFAULT NULL,`deleted_at` datetime(3) DEFAULT NULL,`test_not_null` longtext COLLATE utf8mb4_general_ci NOT NULL,`xxx` longtext COLLATE utf8mb4_general_ci,PRIMARY KEY (`id`),UNIQUE KEY `idx_name_and_code` (`name`,`code`),UNIQUE KEY `uni_user_email` (`email`),KEY `idx_user_birth_date` (`birth_date`),KEY `idx_user_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

3.2 嵌套结构体

可以通过嵌套结构体来实现字段的重用

type Base struct {ID         string `gorm:"primaryKey"`CreateTime time.TimeUpdateTime time.Time
}type Product struct {Base               // 嵌入Base结构体,自动包含CreateTime和UpdateTime字段。gorm.Model         // 框架自带的基础结构体ProductName string `gorm:"type:varchar(100)"`
}

框架自带的基础结构体

// Model a basic GoLang struct which includes the following fields: ID, CreatedAt, UpdatedAt, DeletedAt
// It may be embedded into your model or you may build your own model without it
//
//	type User struct {
//	  gorm.Model
//	}
type Model struct {ID        uint `gorm:"primarykey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt DeletedAt `gorm:"index"`
}

3.3关联关系

GORM 支持各种类型的关联,例如一对一、一对多、多对多等。

3.3.1 一对多

比如一个订单有多个对应的订单明细

type Order struct {gorm.ModelOrderDetail []OrderDetail `gorm:"foreignKey:OrderID"`
}type OrderDetail struct {gorm.ModelOrderID uint
}

3.3.2 一对一

比如一个订单只有一个支付号

type Order struct {gorm.ModelOrderDetail []OrderDetail `gorm:"foreignKey:OrderID"`Payment     Payment       `gorm:"foreignKey:OrderID"`
}type Payment struct {gorm.ModelOrderID string `gorm:"type:varchar(100)"`
}

3.3.3 多对多

比如门店和订单就是多对多关系,这时建立一张id的关联表shop_order,里面只有两个字段shop_id和order_id

type Order struct {gorm.ModelOrderDetail []OrderDetail `gorm:"foreignKey:OrderID"`Payment     Payment       `gorm:"foreignKey:OrderID"`Shops       []Shop        `gorm:"many2many:shop_order"`
}type Shop struct {gorm.ModelOrders []Order `gorm:"many2many:shop_order"`
}

3.3.4 预加载查询

在 GORM 中,关联查询用于处理数据库表之间的关系。GORM 支持多种类型的关系,包括一对一、一对多和多对多。通过使用关联查询,可以轻松地从一个模型导航到相关模型的数据。

type Parent struct {Id   uint   `gorm:"primaryKey"`Name string `gorm:"size:200"`Sons []Son  `gorm:"foreignKey:ParentId"`
}type Son struct {Id       uint   `gorm:"primaryKey"`Name     string `gorm:"size:200"`ParentId string `gorm:"foreignKey"`
}func Test13(t *testing.T) {_ = db.AutoMigrate(Parent{}, Son{})// 简单创建数据db.Create(&Parent{Sons: []Son{{Id:   1,Name: "儿子1",},{Id:   2,Name: "儿子2",},},Name: "父亲",Id:   1,})var parent1 Parentdb.Find(&parent1, 1)fmt.Println(parent1)// 预加载查询var parent2 Parentdb.Preload("Sons").Find(&parent2, 1)fmt.Println(parent2)
}

输出如下,可以看到,没有预加载的话,查询默认是不会获取到子表数据的

{1 父亲 []}
{1 父亲 [{1 儿子1 1} {2 儿子2 1}]}

四、高级应用

4.1 数据库连接池配置

GORM允许你配置数据库连接池,以提高性能和资源管理

使用连接池查询数据与普通的数据库查询没有区别,因为连接池的管理是由底层的 database/sql 包自动处理的。我们只需要专注于编写查询逻辑,GORM 会在后台为你处理连接池。

func Test4(t *testing.T) {sqlDB, err := db.DB()if err != nil {panic("failed to get database")}// 设置最大空闲连接数sqlDB.SetMaxIdleConns(10)// 设置最大打开连接数sqlDB.SetMaxOpenConns(100)// 设置连接可复用的最长时间sqlDB.SetConnMaxLifetime(time.Hour)model := Order{}db.First(model)marshal, _ := json.Marshal(model)fmt.Println(string(marshal))
}

4.2 查询操作

4.2.1 准备数据

type UserInfoTmp struct {ID   uint   `gorm:"primaryKey;autoIncrement"`Name string `gorm:"size:100"`Code string `gorm:"size:100"`
}func Test5(t *testing.T) {_ = db.AutoMigrate(&UserInfoTmp{})db.Create(&UserInfoTmp{Name: "小明1",Code: "x1",})db.Create(&UserInfoTmp{Name: "小明2",Code: "x2",})db.Create(&UserInfoTmp{Name: "小明22",Code: "x22",})db.Create(&UserInfoTmp{Name: "小明333",Code: "x333",})db.Create(&UserInfoTmp{Name: "小明4....",Code: "x4...",})
}

4.2.2 条件查询

支持链式调用进行复杂条件查询

func Test6(t *testing.T) {var users []UserInfoTmpdb.Where("name = ?", "小明1").Or("name = ?", "小明2").Find(&users)fmt.Println(users)db.Not("name", "小明333").Find(&users)fmt.Println(users)db.Where("id BETWEEN ? AND ?", 4, 5).Find(&users)fmt.Println(users)
}

输出

[{1 小明1 x1} {2 小明2 x2}]
[{1 小明1 x1} {2 小明2 x2} {3 小明22 x22} {5 小明4.... x4...}]
[{4 小明333 x333} {5 小明4.... x4...}]

4.2.3 原生SQL查询

可以执行原生SQL语句并将结果映射到模型中:

func Test7(t *testing.T) {var result []UserInfoTmpdb.Raw(`SELECT * FROM user_info_tmp WHERE code like '%3%' or code = ?`, "x22").Scan(&result)fmt.Println(result)
}

输出

[{3 小明22 x22} {4 小明333 x333}]

4.3 更新操作

支持批量更新和条件更新

func Test8(t *testing.T) {// 批量更新所有记录的某个字段值:db.Model(&UserInfoTmp{}).Where("id > ?", 3).Update("Code", gorm.Expr("Concat(`code`,?)", "Extend"))// 使用Map进行批量更新多个列:db.Model(&UserInfoTmp{ID: 3}).Updates(map[string]interface{}{"Name": "XXX", "Code": "xxx"})
}

4.4 删除操作

除了根据主键删除,还可以根据条件删除记录

func Test9(t *testing.T) {// 没有DeletedAt字段时,直接删除db.Delete(&UserInfoTmp{ID: 1})_ = db.AutoMigrate(UserInfoTmp2{})db.Create(&UserInfoTmp2{Name: "XXX"})db.Create(&UserInfoTmp2{Name: "XXX"})// 有DeletedAt类型的字段时,不会硬删db.Delete(&UserInfoTmp2{ID: 1})// 硬删db.Unscoped().Delete(&UserInfoTmp2{ID: 2})// 根据条件删除多条记录db.Where("id > ?", 5).Delete(&UserInfoTmp2{})
}

注意:默认情况下,Delete 方法会执行软删除(即将DeletedAt 字段设置为当前时间),如果要永久删除,可以使用 Unscoped 方法。

4.5 事务处理

事务在需要保证一组数据库操作要么全部成功,要么全部失败时非常有用。

4.5.1 简单事务

func Test10(t *testing.T) {if err := CreateUser(db); err != nil {fmt.Println(err.Error())}
}// 通过事务创建用户
func CreateUser(db *gorm.DB) error {// 通过数据库连接打开一个事务return db.Transaction(func(tx *gorm.DB) error {err := tx.Create(&UserInfoTmp{Name: "测试事务1"})if err.Error != nil {return err.Error}err = tx.Create(&UserInfoTmp2{Name: "测试事务2"})// 可以简单模拟重复失败的情况//err = tx.Create(&UserInfoTmp2{ID: 3, Name: "测试事务2"})if err.Error != nil {return err.Error}// 完成事务return nil})
}

4.5.2 手动管理事务

  1. 启动事务
    使用 db.Begin() 方法启动一个新的事务,它会返回一个新的 *gorm.DB 对象,该对象绑定到当前的数据库连接。
  2. 执行操作
    在返回的事务对象上执行所有需要包含在该事务中的数据库操作。
  3. 提交或回滚
    • 如果所有操作都成功,则调用 tx.Commit() 提交事务。
    • 如果发生错误,则调用 tx.Rollback() 回滚所有更改。
func Test11(t *testing.T) {CreateUserManual(db)
}func CreateUserManual(db *gorm.DB) {begin := db.Begin()defer func() {// 捕获 panic 并确保回滚(防止程序崩溃时未正确处理)if r := recover(); r != nil {begin.Rollback()log.Println("事务提交失败:", r)}}()err := begin.Create(&UserInfoTmp{Name: "测试事务3"})if err.Error != nil {begin.Rollback()}err = begin.Create(&UserInfoTmp2{Name: "测试事务4"})// 模拟panic// err = begin.Create(UserInfoTmp2{Name: "测试事务4"})if err.Error != nil {begin.Rollback()}begin.Commit()}

4.6 钩子函数(Hooks)

钩子函数允许你在特定事件发生前后执行自定义逻辑。例如,在创建、更新或删除之前/之后触发代码逻辑

type TestBeforeCreate struct {Id   string `gorm:"primaryKey"`Name string `gorm:"size:200"`
}func (u *TestBeforeCreate) BeforeCreate(tx *gorm.DB) (err error) {u.Id = uuid.New().String() // 在用户创建之前生成 UUIDreturn
}func Test12(t *testing.T) {_ = db.AutoMigrate(&TestBeforeCreate{})db.Create(&TestBeforeCreate{})
}

uuid使用需要安装库

go get github.com/google/uuid

五、常见报错

type UserInfoTmp struct {ID   uint `gorm:"primaryKey;autoIncrement"`Name string
}func Test5(t *testing.T) {_ = db.AutoMigrate(&UserInfoTmp{})db.Create(UserInfoTmp{Name: "小明",})
}

执行以上代码会报错:

panic: reflect: reflect.Value.SetUint using unaddressable value [recovered]panic: reflect: reflect.Value.SetUint using unaddressable value

这是因为 GORM 无法设置自增主键字段,因为它需要通过反射修改原始对象。将 UserInfoTmp 的实例作为指针传递给 db.Create() 方法,GORM 才可以正确地更新对象中的字段。

db.Create(&UserInfoTmp{Name: "小明",})

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

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

相关文章

多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码

一、麋鹿优化算法 麋鹿优化算法(Elephant Herding Optimization,EHO)是2024年提出的一种启发式优化算法,该算法的灵感来源于麋鹿群的繁殖过程,包括发情期和产犊期。在发情期,麋鹿群根据公麋鹿之间的争斗分…

Word窗体联动Excel实现级联组合框

在Word中的使用用户窗体(UserForm)定制界面如下图所示,其中控件如下(忽略Label控件): CompanyName 组合框Attention 组合框CommandButton1 按钮 现在需要实现级联组合框效果,即用户在 CompanyN…

浅谈TARA在汽车网络安全中的关键角色

随着现代汽车技术的迅猛发展,网络安全成为汽车行业一个不可忽视的领域。为了应对日益复杂的网络威胁,ISO/SAE 21434标准和UN R155法规提供了系统化的网络安全管理框架。其中,TARA(威胁分析与风险评估)作为核心方法论&a…

领克Z20结合AI技术,革新自动驾驶辅助系统

眼瞅着,再有不到 5 个星期,春节就要热热闹闹地登场啦!对于在外辛苦打拼了一整年的打工人而言,回家过年可不就是这一年里心心念念、最最期盼的高光时刻嘛。这不,这几天各地的高速公路愈发熙熙攘攘起来,川流不…

C语言结构体位定义(位段)的实际作用深入分析

1、结构体位段格式 struct struct_name {type [member_name] : width; };一般定义结构体,成员都是int、char等类型,占用的空间大小是固定的在成员名称后用冒号来指定位宽,可以指定每个成员所占用空间,并且也不用受结构体成员起始…

Android--java实现手机亮度控制

文章目录 1、开发需求2、运行环境3、主要文件4、布局文件信息5、手机界面控制代码6、debug 1、开发需求 需求:开发一个Android apk实现手机亮度控制 2、运行环境 Android studio最新版本 3、主要文件 app\src\main\AndroidManifest.xml app\src\main\res\layou…

Modbus数据网关在制造企业的应用与效果

Modbus是一种广泛应用于工业通信的协议,支持多种设备间的数据交换,如传感器、仪器仪表、PLC、工业机器人、数控机床等。Modbus数据网关则是一种网络通信转换设备,它能够将Modbus协议的数据转换为其他主流协议(如MQTT、OPC UA、HTT…

秒鲨后端之MyBatis【2】默认的类型别名、MyBatis的增删改查、idea中设置文件的配置模板、MyBatis获取参数值的两种方式、特殊SQL的执行

别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! 下篇更新&#xff1a; 秒鲨后端之MyBatis【3】自定义映射resultMap、动态SQL、MyBatis的缓存、MyBatis的逆向工程、分页插件。 默认的类型别名 MyBatis的增删改查 添加 <!--int insertUs…

从数据仓库到数据中台再到数据飞轮:电信行业的数据技术进化史

前言 大家好&#xff0c;我是一名大数据开发工程师&#xff0c;电信行业作为高度数据驱动的行业&#xff0c;长期以来通过技术创新不断优化服务质量和业务运营。从最早期的数据仓库&#xff0c;到数据中台&#xff0c;再到如今的数据飞轮&#xff0c;电信行业的数据技术经历了几…

【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111

文章目录 一、算法概念111二、算法原理&#xff08;一&#xff09;感知机&#xff08;二&#xff09;多层感知机1、隐藏层2、激活函数sigma函数tanh函数ReLU函数 3、反向传播算法 三、算法优缺点&#xff08;一&#xff09;优点&#xff08;二&#xff09;缺点 四、MLP分类任务…

【NLP高频面题 - 高效微调篇】什么是提示微调?

【NLP高频面题 - 高效微调篇】什么是提示微调&#xff1f; 重要性&#xff1a;★ NLP Github 项目&#xff1a; NLP 项目实践&#xff1a;fasterai/nlp-project-practice 介绍&#xff1a;该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用&#xff0c;分享大模型算法…

基于kraft部署kafka集群

kafka介绍 Apache Kafka 是一个开源的分布式事件流平台&#xff0c;被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用。 Kafka是一个拥有高吞吐、可持久化、可水平扩展&#xff0c;支持流式数据处理等多种特性的分布式消息流处理中间件&#xff0c;采用分布式…

debug diagnostic tool 调试.net的错误

下载安装debug diagnostic tool debug diagnostic tool 设置 因为现在都是多cpu,所以cpu可以设置低一点,就抓去数据 微软教程

京东科技基于 Apache SeaTunnel 复杂场景适配 #数据集成

作者&#xff1a;宁诚、陈伟强 京东科技架构师 技术背景与挑战 技术背景 2023年第一季度&#xff0c;京东科技的营销与数据资产部开始规划数据洞察系统产品&#xff0c;主要服务于京东科技营销体系的业务团队。该系统的分析内容涵盖了京东集团在商城、金融和物流等各个业务系…

基于Spring Boot的工商局商家管理系统

一、系统背景与意义 随着市场经济的不断发展&#xff0c;商家数量日益增多&#xff0c;工商局对商家的管理需求也日益复杂。传统的管理方式存在诸多弊端&#xff0c;如信息不透明、管理效率低下等。因此&#xff0c;开发一种高效、便捷、智能化的工商局商家管理系统显得尤为重…

论文DiffBP: generative diffusion of 3D molecules for target protein binding

研究背景 在药物发现中&#xff0c;生成能与特定蛋白质结合的分子至关重要但极具挑战。以往的工作大多采用自回归方式逐个生成原子的元素类型和三维坐标&#xff0c;但在真实分子系统中&#xff0c;原子间的相互作用是全局性的&#xff0c;基于能量考虑&#xff0c;概率建模应基…

如何在谷歌浏览器中进行网络速度测试

在当今高度依赖互联网的时代&#xff0c;网络速度的快慢直接影响着我们的工作、学习和娱乐等各个方面。因此&#xff0c;了解如何准确测试网络速度成为了每个网民应掌握的基本技能。谷歌浏览器作为一款广泛使用的浏览器&#xff0c;提供了便捷且高效的网络速度测试功能。本文将…

JAVAweb学习日记(三)Ajax

一、Ajax Axios&#xff1a; 入门&#xff1a; 案例&#xff1a; 二、前后端分离开发 介绍&#xff1a; APIfox&#xff1a; Apifox 前端工程化&#xff1a; 环境准备&#xff1a; Vue项目-创建&#xff1a; Vue项目-配置端口&#xff1a; Vue项目-开发流程&#xff1a; Vue…

聊天社交管理系统 Java 源码,构建个性化社交空间

社交网络已经是我们生活中非常重要的一部分&#xff0c;一个高效、个性化的聊天社交管理系统都能极大提升用户体验。 多种消息通知类型&#xff0c;支持新消息通知&#xff0c;图标闪烁、声音提醒和弹窗提醒。 1.音视频&#xff1a; 支持二人聊天&#xff0c;有语音聊天、桌面…

Shion(时间追踪工具) v0.13.2

Shion 是一款多功能的时间追踪软件&#xff0c;旨在帮助用户更好地管理时间。它提供了多种自定义数据卡片&#xff0c;如github风格的一年概览、30天单项数据柱状图和每日24小时活动展示&#xff0c;以便用户清晰地了解自己的日常生活。Shion还具备自动监听程序使用时间的功能&…