当前位置: 首页 > news >正文

go gorm简单使用方法

GORM 是 Go 语言中一个非常流行的 ORM(对象关系映射)库,它允许开发者通过结构体来定义数据库表结构,并提供了丰富的 API 来操作数据库。
安装

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

表结构

gorm 中定义表结构通常是通过定义一个结构体(struct)来完成的,其中每个字段对应数据库表中的列。

以下是一个使用 GORM 定义的简单用户表结构的例子:

package mainimport ("gorm.io/gorm""gorm.io/dialects/mysql"
)// User 定义了用户的表结构
type User struct {// gorm.Model 包含了一些默认字段:ID, CreatedAt, UpdatedAt, DeletedAtgorm.Model// 用户名,设置为唯一且不能为空Name string `gorm:"column:user_name;type:varchar(50);unique;not null"`// 手机号,设置为唯一且不能为空Phone string `gorm:"type:varchar(20);unique;not null"`// 密码,存储为二进制大对象Password []byte `gorm:"type:blob" json:"-"`
}func main() {// 连接数据库dsn := "user:password@tcp(127.0.0.1:3306)/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.AutoMigrate(&User{})
}

在这个例子中:

  • gorm.Model 是一个便捷的结构体,包含了 ID, CreatedAt, UpdatedAt, DeletedAt 字段。
  • NamePhone 字段设置了数据库列名、类型、是否唯一以及是否可以为空。
  • Password 字段被设置为 blob 类型,并且不包含在 JSON 序列化中。
  • dsn (Data Source Name) 是用来连接 MySQL 数据库的字符串。
  • db.AutoMigrate(&User{}) 会自动根据 User 结构体创建或更新对应的数据库表结构。

在 GORM 中,单表操作包括创建、查询、更新和删除记录。以下是一些基本的单表操作示例:

单表操作

创建记录

创建记录通常使用 Create 方法。

// 创建一个新的 User 实例
user := User{Name: "张三", Age: 30, Email: "zhangsan@example.com"}
// 使用 Create 方法创建记录
result := db.Create(&user)
// 检查错误
if result.Error != nil {panic(result.Error)
}
// 输出插入后的用户 ID
fmt.Printf("插入后的用户 ID: %d\n", user.ID)

查询记录

查询记录可以使用 First, Find, Take, Last 等方法。

查询第一个匹配的记录

// 查询第一个用户
var user User
result := db.First(&user)
if result.Error != nil {panic(result.Error)
}
fmt.Printf("查询到的用户: %+v\n", user)

查询所有记录

// 查询所有用户
var users []User
result := db.Find(&users)
if result.Error != nil {panic(result.Error)
}
fmt.Printf("查询到的用户列表: %+v\n", users)

条件查询

// 查询年龄为 30 的用户
var user User
result := db.Where("age = ?", 30).First(&user)
if result.Error != nil {panic(result.Error)
}
fmt.Printf("查询到的用户: %+v\n", user)

更新记录

更新记录通常使用 UpdateUpdates 方法。

更新单个字段

// 更新第一个用户的年龄
result := db.Model(&User{}).Where("id = ?", 1).Update("age", 31)
if result.Error != nil {panic(result.Error)
}
fmt.Printf("更新影响的行数: %d\n", result.RowsAffected)

更新多个字段

// 更新第一个用户的年龄和邮箱
result := db.Model(&User{}).Where("id = ?", 1).Updates(User{Age: 32, Email: "zhangsan_new@example.com"})
if result.Error != nil {panic(result.Error)
}
fmt.Printf("更新影响的行数: %d\n", result.RowsAffected)

删除记录

删除记录使用 Delete 方法。

// 删除 ID 为 1 的用户
result := db.Delete(&User{}, 1)
if result.Error != nil {panic(result.Error)
}
fmt.Printf("删除影响的行数: %d\n", result.RowsAffected)

软删除

如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力

当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。

查找被删除的记录

DB.Unscoped().Find(&users)

永久删除

db.Unscoped().Delete(&user)

单标高级查询

条件查询

Where 子句

// 查询年龄大于 30 的用户
var users []User
db.Where("age > ?", 30).Find(&users)

Struct & Map 条件

// 使用结构体作为条件
db.Where(&User{Name: "张三", Age: 30}).Find(&users)
// 使用 Map 作为条件
db.Where(map[string]interface{}{"name": "张三", "age": 30}).Find(&users)

Not 条件

// 查询年龄不等于 30 的用户
db.Not("age = ?", 30).Find(&users)

Or 条件

// 查询年龄大于 30 或者名字是李四的用户
db.Where("age > ?", 30).Or("name = ?", "李四").Find(&users)

内联条件

// 内联条件查询
db.Find(&users, "age > ?", 30)

Select 子句

// 仅查询特定字段
db.Select("name", "age").Find(&users)

Order By

// 根据年龄排序
db.Order("age desc").Find(&users)

Limit & Offset

// 限制返回结果的数量,并设置偏移量
db.Limit(10).Offset(20).Find(&users)

Count

// 计算符合条件的记录数量
var count int64
db.Where("age > ?", 20).Model(&User{}).Count(&count)

Group By & Having

// 分组并使用 Having 子句
db.Model(&User{}).Select("name, sum(age) as total_age").Group("name").Having("total_age > ?", 100).Find(&users)

Joins

// 内连接查询
db.Joins("JOIN orders ON orders.user_id = users.id").Where("orders.status = ?", "paid").Find(&users)

Scopes

// 定义一个 Scope
func AgeGreaterThan(age int) func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {return db.Where("age > ?", age)}
}
// 使用 Scope 查询
db.Scopes(AgeGreaterThan(30)).Find(&users)

Pluck

// 提取单个列的值
var ages []int
db.Model(&User{}).Pluck("age", &ages)

Scan

// 将查询结果映射到不同的结构体
type Result struct {Name stringAge  int
}
var result Result
db.Model(&User{}).Select("name, age").Where("id = ?", 1).Scan(&result)

多表关系与操作

在 GORM 中处理多表关系和多表操作是非常直观的,它支持多种关系类型,如一对一、一对多、多对多等

定义多表关系

一对一关系 (One-to-One)

假设我们有一个 User 模型和一个 Profile 模型,每个用户只有一个个人资料。

type User struct {gorm.ModelName  stringProfile Profile
}type Profile struct {gorm.ModelUserID uintBio    string
}

这里 Profile 表通过 UserID 字段与 User 表关联。

一对多关系 (One-to-Many)

假设我们有一个 User 模型和一个 Order 模型,每个用户可以有多个订单。

type User struct {gorm.ModelName  stringOrders []Order
}type Order struct {gorm.ModelUserID uintAmount float64
}

这里 Order 表通过 UserID 字段与 User 表关联。

多对多关系 (Many-to-Many)

假设我们有一个 User 模型和一个 Language 模型,每个用户可以掌握多种语言,每种语言也可以被多个用户掌握。

type User struct {gorm.ModelName     stringLanguages []Language `gorm:"many2many:user_languages;"`
}type Language struct {gorm.ModelName string
}

这里使用了一个中间表 user_languages 来存储 UserLanguage 之间的关系。

多表操作

创建关联记录

对于一对一和一对多的关系,你可以直接创建并保存关联的模型:

// 创建用户及其个人资料
func createUserWithProfile(db *gorm.DB) {db.Create(&User{Name: "John Doe",Profile: Profile{Bio: "Hello, I'm John"},})
}// 创建用户及其订单
func createUserWithOrders(db *gorm.DB) {db.Create(&User{Name: "Jane Doe",Orders: []Order{{Amount: 100.0},{Amount: 200.0},},})
}

对于多对多的关系,你需要先创建两边的模型,然后再建立它们之间的关系:

// 创建用户及其语言
func createUserWithLanguages(db *gorm.DB) {user := User{Name: "Alice"}languages := []Language{{Name: "English"}, {Name: "Spanish"}}// 先创建用户和语言db.Create(&user)for i := range languages {db.Create(&languages[i])}// 建立关系db.Model(&user).Association("Languages").Append(languages)
}

查询关联数据

GORM 支持预加载(Preloading)来一次性加载关联的数据:

// 预加载用户的个人资料
func getUserWithProfile(db *gorm.DB, userID uint) {var user Userdb.Preload("Profile").First(&user, userID)log.Printf("User: %+v, Profile: %+v", user, user.Profile)
}// 预加载用户的订单
func getUserWithOrders(db *gorm.DB, userID uint) {var user Userdb.Preload("Orders").First(&user, userID)log.Printf("User: %+v, Orders: %+v", user, user.Orders)
}// 预加载用户的语言
func getUserWithLanguages(db *gorm.DB, userID uint) {var user Userdb.Preload("Languages").First(&user, userID)log.Printf("User: %+v, Languages: %+v", user, user.Languages)
}

更新关联数据

更新关联数据通常涉及添加或移除关联项:

// 添加新的语言给用户
func addUserLanguage(db *gorm.DB, userID uint, languageID uint) {var user Userdb.First(&user, userID)db.Model(&user).Association("Languages").Append(&Language{Model: gorm.Model{ID: languageID}})
}// 从用户中移除一种语言
func removeUserLanguage(db *gorm.DB, userID uint, languageID uint) {var user Userdb.First(&user, userID)db.Model(&user).Association("Languages").Delete(&Language{Model: gorm.Model{ID: languageID}})
}

删除关联数据

删除关联数据时,可以选择级联删除或只是删除关联本身:

// 删除用户及其所有订单
func deleteUserAndOrders(db *gorm.DB, userID uint) {db.Delete(&User{}, userID)
}// 只删除用户的某个订单
func deleteOrder(db *gorm.DB, orderID uint) {db.Delete(&Order{}, orderID)
}// 删除用户及其所有语言关联
func deleteUserAndLanguages(db *gorm.DB, userID uint) {db.Delete(&User{}, userID)
}

事务

在 GORM 中,事务用于确保数据库操作的原子性,这意味着要么所有操作都成功执行,要么在遇到错误时所有操作都不会对数据库产生影响。以下是如何在 GORM 中使用事务的示例:

开始事务

在 GORM 中,你可以使用 Begin 方法来开始一个新的事务。

tx := db.Begin() // 开始事务

在事务中执行操作

在事务中,你可以执行任何你通常会在 GORM 中执行的操作,例如创建、更新、删除等。

user := User{Name: "张三", Age: 30}
if err := tx.Create(&user).Error; err != nil {tx.Rollback() // 遇到错误时回滚事务return err
}
post := Post{Title: "事务测试", Content: "这是一个事务中的帖子", UserID: user.ID}
if err := tx.Create(&post).Error; err != nil {tx.Rollback() // 遇到错误时回滚事务return err
}

提交事务

如果所有操作都成功执行,你可以调用 Commit 方法来提交事务。

if err := tx.Commit().Error; err != nil {return err // 提交事务时出错
}

回滚事务

如果在事务中的任何操作失败,你应该调用 Rollback 方法来回滚所有更改。

if err := tx.Rollback().Error; err != nil {return err // 回滚事务时出错
}

使用 Transaction 方法

GORM 还提供了一个 Transaction 方法,它接受一个函数作为参数,这个函数将在事务的上下文中执行。如果函数返回错误,事务将自动回滚;如果没有错误,事务将自动提交。

err := db.Transaction(func(tx *gorm.DB) error {user := User{Name: "李四", Age: 28}if err := tx.Create(&user).Error; err != nil {return err // 返回任何错误都会回滚事务}post := Post{Title: "另一个事务测试", Content: "这是另一个事务中的帖子", UserID: user.ID}if err := tx.Create(&post).Error; err != nil {return err // 返回任何错误都会回滚事务}return nil // 返回 nil 提交事务
})
if err != nil {// 事务回滚,处理错误
}

使用 Transaction 方法可以简化事务的处理,因为它自动处理了提交和回滚的逻辑。

相关文章:

go gorm简单使用方法

GORM 是 Go 语言中一个非常流行的 ORM(对象关系映射)库,它允许开发者通过结构体来定义数据库表结构,并提供了丰富的 API 来操作数据库。 安装 go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite表结构 在 gorm 中定义表结…...

【c++高级篇】--多任务编程/多线程(Thread)

目录 1.进程和线程的概念: 1.1 进程(Process): 1.2线程(Thread): 1.3 对比总结: 2.多线程编程: 2.1 基于线程的多任务处理(Thread)&#xf…...

【力扣专题栏】两数相加,如何实现存储在链表中的整数相加?

题解目录 1、题目描述解释2、算法原理解析3、代码编写(原始版本)4、代码编写(优化版本) 1、题目描述解释 2、算法原理解析 3、代码编写(原始版本) /*** Definition for singly-linked list.* struct ListN…...

SOLID - 接口隔离原则(Interface Segregation Principle)

SOLID - 接口隔离原则(Interface Segregation Principle) 定义 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的五个基本原则之一,通常缩写为SOLID中的I。这一原则由Robert C. Martin提出&…...

arrylist怎么让他变得不可修改

在Java中,要将一个 ArrayList变得不可修改,你可以使用以下几种方法: ###1. 使用 Collections.unmodifiableList Java 提供了 Collections.unmodifiableList 方法,可以生成一个不可修改的视图。这种方式返回的列表将不允许添加、…...

SpringMVC实战(3):拓展

四、RESTFul风格设计和实战 4.1 RESTFul风格概述 4.1.1 RESTFul风格简介 RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议&…...

Vue应用中使用xlsx库实现Excel文件导出的完整指南

Vue应用中使用xlsx库实现Excel文件导出的完整指南 在现代Web开发中,经常需要将数据导出为Excel文件,以便于用户进行离线分析或记录。Vue.js作为一个轻量级且高效的前端框架,结合xlsx库可以轻松实现这一功能。本文将详细介绍如何在Vue应用中使…...

【数据分析】Power BI的使用教程

目录 1 Power BI架构1.1 Power BI Desktop1.2 Power BI服务1.3 Power BI移动版 2 Power Query2.1 Power Query编辑器2.2 Power Query的优点2.3 获取数据2.4 数据清洗的常用操作2.4.1 提升标题2.4.2 更改数据类型2.4.3 删除错误/空值2.4.4 删除重复项2.4.5 填充2.4.6 合并列2.4.…...

融合ASPICE与敏捷开发:探索汽车软件开发的最佳实践

ASPICE(Automotive SPICE,即汽车软件过程改进和能力dEtermination)与敏捷开发在软件开发领域各自具有独特的价值和特点,它们之间的关系可以归纳为既相互区别又相互补充。 一、ASPICE的特点 ASPICE是汽车行业对软件开发流程的一个评…...

后台管理系统的通用权限解决方案(三)SpringBoot整合Knife4j生成接口文档

1 Knife4j介绍 knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名knife4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍! 其底层是对Springfox的封装,使…...

保研考研机试攻略:python笔记(1)

🐨🐨🐨宝子们好呀 ~ 我来更新欠大家的python笔记了,从这一篇开始我们来学下python,当然,如果只是想应对机试并且应试语言以C和C为主,那么大家对python了解一点就好,重点可以看高分篇…...

在浏览器中运行 Puppeteer:解锁新能力

Puppeteer,这个强大的浏览器自动化工具,通常在Node.js环境中运行。但你有没有想过,在浏览器本身中运行Puppeteer会是什么样子?这不仅能让我们利用Puppeteer的功能完成更多任务,还能避开Node.js特定的限制。 支持的功…...

Kafka消费者故障,出现活锁问题如何解决?

大家好,我是锋哥。今天分享关于【Kafka消费者故障,出现活锁问题如何解决?】面试题?希望对大家有帮助; Kafka消费者故障,出现活锁问题如何解决? 1000道 互联网大厂Java工程师 精选面试题-Java资…...

pytorch 交叉熵损失函数 BCELoss

BCE Loss 交叉熵损失函数计算公式: BCE Loss - 1/n*(y_actual * log(y_pred) (1 - y_actual) * log(1 - y_pred)) t[i]为标签值:0或者1 o[i]是经过sigmoid后的概率值 BCEWithLogitsLoss 这个损失将Sigmoid层和BCELoss合并在一个类中。 BCEWithLog…...

【进阶】面向对象之接口(多学三招)

文章目录 IDK8开始接口中新增的方法1.允许在接口中定义默认方法,需要使用关键字default修饰2.接口中的默认方法的定义格式3.接口中默认方法的注意事项总结 IDK8开始接口中新增的方法 JDK7以前:接口中只能定义抽象方法。JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态…...

linux上trace code的几种方法

我们在看代码时,总是会遇到下面问题: 1.查看某个场景下的代码执行流 2.查看某个函数被执行时的routine 但是,如果直接查看源码,源码可能代码量大,且分支多,不容易理清。就需要让相关程序运行起来查看。 …...

文件操作(1) —— 文件基础知识

目录 1. 为什么使用文件? 2. 文件种类【按功能分】 3. 文件名 4. 数据文件种类【按存储方式细分】 5. 文件的打开和关闭 5.1 流和标准流 5.2 文件指针 5.3 文件的打开和关闭函数 6. 文件缓冲区 1. 为什么使用文件? 如果没有⽂件,我…...

4K双模显示器7款评测报告

4K双模显示器7款评测报告 HKC G27H7Pro 4K双模显示器 ROG华硕 XG27UCG 4K双模显示器 雷神 ZU27F160L 4K双模显示器 泰坦军团 P275MV PLUS 4K双模显示器 外星人(Alienware)AW2725QF 4K双模显示器 SANC盛色 D73uPro 4K双模显示器 ANTGAMER蚂蚁电竞 …...

2024.10.24华为(留学生)笔试题解

第一题集装箱堆叠 看注释即可 // 看题目,是最长连续序列的变种。底应该选大的,然后往上堆叠选择次大的(越接近底越好?) // 后续想一下,像是动态规划? // 再一想,好像排序后很容易处理#include <bits/stdc++.h> #include <functional> using namespace st…...

基于neo4j的医疗问诊系统

当你身体不适时&#xff0c;想要找到准确的答案却经常遇到模棱两可的答复&#xff0c;糟心吗&#xff1f;现在&#xff0c;基于neo4j的智能医疗问诊系统为你带来全新体验&#xff01;我们设计了一个具备自动化问答功能的医疗系统&#xff0c;帮助用户快速获取专业的健康知识答案…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...