快速学习gorm 框架

2024-08-22 15:12
文章标签 学习 快速 框架 gorm

本文主要是介绍快速学习gorm 框架,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

go-orm

介绍

godemo是一款go目前主流的orm框架

软件架构

官方文档 GORM - The fantastic ORM library for Golang, aims to be developer friendly.

使用说明

安装教程

1.设置代理

go env -w  GOPROXY=https://goproxy.cn,direct

2.打算使用gin 搭配gorom 进行学习模拟web开发

## 安装gin
go get -u github.com/gin-gonic/gin
#数据库驱动和orm
go get gorm.io/driver/mysql
go get gorm.io/gorm

连接

数据库连
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情dsn := "用户名:密码@tcp(127.0.0.1:3306)/数据库名?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

添加配置 自定义驱动


import (_ "example.com/my_mysql_driver""gorm.io/driver/mysql""gorm.io/gorm"
)db, err := gorm.Open(mysql.New(mysql.Config{DriverName: "my_mysql_driver",DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name, 详情参考:https://github.com/go-sql-driver/mysql#dsn-data-source-name
}), &gorm.Config{})
	// 日志配置var mysqlLogger logger.Interface// 要显示的日志等级mysqlLogger = logger.Default.LogMode(logger.Info)db, _ := gorm.Open(mysql.New(mysql.Config{// leave blank for default driverDSN: "root:111111@tcp(127.0.0.1:3306)/ruiji?charset=utf8&parseTime=True&loc=Local", // data source name, 详情参考:https://github.com/go-sql-driver/mysql#dsn-data-source-name}), &gorm.Config{Logger:                 mysqlLogger, //注册SkipDefaultTransaction: true,        // 禁用默认事务})sqlDB, _ := db.DB()// 设置空闲连接池中的最大连接数。ol.sqlDB.SetMaxIdleConns(10)// 设置与数据库的最大打开连接数sqlDB.SetMaxOpenConns(100)// 设置可以重复使用连接的最长时间。sqlDB.SetConnMaxLifetime(time.Hour)

CRUD

假如有model


type Student struct {ID uint // 默认使用ID作为主键//设置字段长度为2Name  string  `gorm:"size:10"`Sex   string  `gorm:"size:2"`Email *string // 使用指针是为了存空值Age   int
}

gorm中的tag约束 除开上述 还有以下 可以做到创建表时候约束

创建表

如果存在也不会报错 如果结构体和数据库模型 不一样则执行的是alter 更改数据库的操作

使用 AutoMigrate 方法自动迁移你的 schema,这将会创建数据库中不存在的表。
db.AutoMigrate(&Product{})

插入数据

单挑数据插入

db.Create(s) s是该映射结构体的指针

func insertStudent(c *gin.Context) {s := new(Student)if err := c.ShouldBindQuery(s); err != nil {return} else {db.Create(s)c.JSON(200, gin.H{"data":    s,"message": "创建用户成功",})}
}

批量插入 同样 参数传递结构体切片即可

func bentchInserter(c *gin.Context) {students := make([]Student, 10)for i := 1; i <= 20; i++ {students = append(students, Student{Name: "测试" + strconv.Itoa(i),Age:  i,Sex:  "男",//Email: nil,})}db.Create(&students)c.JSON(200, gin.H{"data":    students,"message": "批量创建用户成功",})
}

插入后该指针结构体的id字段就会被填充

删除

api delete

//第一个参数 是映射结构体指针 第二个参数是id 只有空结构体指针时候代表删除全表 
db.Delete(s, id)

等效

s.ID = uint(parsedID)
db.Delete(s) 

Or where 拼接查询条件 可以使用?方式进行拼接sql

	db.Or("age<?", 18).Where("name", "测试张三").Delete(s, id) // 根据主键删除

日志

[4.352ms] [rows:1] DELETE FROM students WHERE name = ‘测试张三’ AND students.id = ‘1’

注意

gorm 对于不携带条件的批量修改字段 比如UPDATE students SET sex=‘妈妈’() ,DELETE FROM students 这俩个sql正常来说是会改变整个表的记录,但是gorom 并不会去执行

sql1 go中的api

s := new(Student)
db.Model(s).Update("sex", "妈妈")

sq2

db.Delete(s)

但是加一个简单的条件

db.Model(s).Where("1 = 1").Update("sex", "男")

[7.314ms] [rows:26] UPDATE students SET sex=‘男’ WHERE 1 = 1 日志输出却可以成功改变全表记录

GORM 中无条件批量操作的行为总结

在 GORM 中,某些批量操作(如 DeleteUpdate)具有防护机制,以防止意外更改整个数据库。以下是关键行为的总结:

  1. 无条件删除
    • 当你尝试在不指定条件的情况下删除记录时,GORM 可能会生成类似 DELETE FROM 'students' 的 SQL 语句,但实际上不会删除任何记录。输出会显示 rows:0,以防止意外的大规模删除操作。
  2. 无条件更新
    • 使用 Struct 和 Updates 当你使用 db.Model(&Student{}).Updates(Student{Sex: "未"}) 时,GORM 会尝试更新表中所有记录的字段。但它会执行检查,避免在没有条件的情况下进行大规模更新。如果没有指定条件,这种操作通常不会执行。
    • 使用 Update 更新单个字段: 如果你执行 db.Model(&Student{}).Update("sex", "未"),GORM 的日志会显示它计划更新所有记录的 sex 字段,但如果没有明确的条件,它仍不会执行。
  3. 使用虚拟条件的操作
    • 使用虚拟条件: 通过添加像 db.Model(s).Where("1 = 1").Update("sex", "妈妈") 这样的条件,更新操作会执行,因为存在条件(即使是一个简单的条件)。

关键提示

映射指针没有id就是全表操作 有id 还设置id查询条件就是and 拼接

修改

修改单个字段 update api

s := &Student{ID: uint(id)} // 创建 Student 结构体并设置 ID  无论批量还是单个更新值字段,都需要id 不然无法找到数据
//如果没有id 就是对全表操作 但是没有条件的全表操作不会执行db.Model(s).Update("sex", "未") 

修改多个字段 updates api

db.Model(s).Where("id = ?", id).Where("age > ?", 10).Updates(Student{Name: "测试张三", Age: 18, Sex: "男"}) // 根据主

批量修改全表,只需要一个空结构体映射指针和简单的条件

db.Model(s).Where("1 = 1").Updates(Student{Name: "测试张三", Age: 18, Sex: "男"})

查询

单记录

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error or nil// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)

批量 find


// Get all matched records
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

虽然go中有select来简写查询语句 但是我还是喜欢where拼接的方式

DB.Select("name", "age").Find(&users)

在 GORM 中,Scan 方法用于将查询结果扫描到 Go 变量中。它允许你执行原始 SQL 查询,并将查询结果填充到指定的结构体或切片中。Scan 方法通常与 Raw 方法结合使用,用于处理更复杂的 SQL 查询。

可以根据这个方法来写原生sql

db.Raw("SELECT * FROM students WHERE id = ?", 1).Scan(&student)
分组查询
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
分页查询
// 一页两条,第1页
DB.Limit(2).Offset(0).Find(&users)
fmt.Println(users)
// 第2页
DB.Limit(2).Offset(2).Find(&users)
fmt.Println(users)
// 第3页   pagesize*(页号-1)
DB.Limit(2).Offset(4).Find(&users)
fmt.Println(users)
多表联查

下面是之前示例的 GORM 代码,并在每个示例的注释中添加了对应的 SQL 转换。

1. 多表联查 (JOIN Queries)
var users []User
db.Joins("JOIN orders ON orders.user_id = users.id").Where("orders.status = ?", "completed").Find(&users)// SQL: SELECT * FROM users 
//      JOIN orders ON orders.user_id = users.id 
//      WHERE orders.status = 'completed';
2. 范围查询 (Range Queries)
var orders []Order
db.Where("created_at BETWEEN ? AND ?", startDate, endDate).Find(&orders)// SQL: SELECT * FROM orders 
//      WHERE created_at BETWEEN 'startDate' AND 'endDate';
3. 子查询 (Subqueries)
subQuery := db.Table("orders").Select("AVG(amount)").Where("user_id = ?", userID).SubQuery()var orders []Order
db.Where("amount > ?", subQuery).Find(&orders)// SQL: SELECT * FROM orders 
//      WHERE amount > (SELECT AVG(amount) FROM orders WHERE user_id = userID);
4. 多条件复杂查询 (Complex Queries with Multiple Conditions)
var users []User
db.Where("age BETWEEN ? AND ?", minAge, maxAge).Where("region = ?", region).Where("status = ?", "active").Find(&users)// SQL: SELECT * FROM users 
//      WHERE age BETWEEN minAge AND maxAge 
//      AND region = 'region' 
//      AND status = 'active';
5. 联合查询 (UNION Queries)
var results []User
db.Raw("SELECT * FROM users WHERE region = ? UNION SELECT * FROM users WHERE region = ?", region1, region2).Scan(&results)// SQL: SELECT * FROM users WHERE region = 'region1' 
//      UNION 
//      SELECT * FROM users WHERE region = 'region2';
6. 预加载和条件加载 (Preload with Conditions)
var users []User
db.Preload("Orders", "status = ?", "completed").Find(&users)// SQL: SELECT * FROM users; 
//      SELECT * FROM orders WHERE user_id IN (userIDs) AND status = 'completed';
7. 分组与聚合查询 (Group By and Aggregate Functions)
type Result struct {UserID uintCount  int
}var results []Result
db.Model(&Order{}).Select("user_id, COUNT(*) as count").Group("user_id").Having("count > ?", 5).Find(&results)// SQL: SELECT user_id, COUNT(*) as count 
//      FROM orders 
//      GROUP BY user_id 
//      HAVING count > 5;
8. 关联表条件查询 (Conditions on Related Tables)
var users []User
db.Joins("JOIN orders ON orders.user_id = users.id").Joins("JOIN order_items ON order_items.order_id = orders.id").Joins("JOIN products ON products.id = order_items.product_id").Where("products.name = ?", "Product A").Find(&users)// SQL: SELECT users.* FROM users 
//      JOIN orders ON orders.user_id = users.id 
//      JOIN order_items ON order_items.order_id = orders.id 
//      JOIN products ON products.id = order_items.product_id 
//      WHERE products.name = 'Product A';
9. 使用 Raw SQL 实现复杂查询 (Using Raw SQL for Complex Queries)
var orders []Order
db.Raw("SELECT * FROM orders WHERE user_id = ? AND amount > ? ORDER BY created_at DESC", userID, minAmount).Scan(&orders)// SQL: SELECT * FROM orders 
//      WHERE user_id = userID 
//      AND amount > minAmount 
//      ORDER BY created_at DESC;
10. 分页查询 (Pagination Queries)
var orders []Order
db.Where("user_id = ?", userID).Limit(10).Offset(20).Order("created_at DESC").Find(&orders)// SQL: SELECT * FROM orders 
//      WHERE user_id = userID 
//      ORDER BY created_at DESC 
//      LIMIT 10 OFFSET 20;

gorm中有很多相似的api 但是大致都可以实现想要的sql效果下面总结一下

Find
  • 功能:用于查询表中的所有记录或符合条件的记录,并将结果扫描到切片中。

  • 用法

    var students []Student
    db.Find(&students)
    

    你也可以结合条件使用 Find

    db.Where("age > ?", 18).Find(&students)
    
  • 适用场景:用于检索表中的多条记录,结果会自动填充到结构体切片中。

2. First
  • 功能:查询表中的第一条记录(按主键排序)。

  • 用法

    var student Student
    db.First(&student)
    

    你也可以结合条件使用 First

    
    db.Where("id = ?", 1).First(&student)
    
  • 适用场景:用于检索表中的单条记录(通常是按主键或条件查询到的第一条记录)。

3. Last
  • 功能:查询表中的最后一条记录(按主键排序)。

  • 用法

    var student Student
    db.Last(&student)
    

    你也可以结合条件使用 Last

    
    db.Where("age > ?", 18).Last(&student)
    
  • 适用场景:用于检索表中的最后一条记录(通常是按主键或条件查询到的最后一条记录)。

4. Take
  • 功能:查询表中的任意一条记录(不一定是第一条)。

  • 用法

    var student Student
    db.Take(&student)
    

    你也可以结合条件使用 Take

    
    db.Where("age > ?", 18).Take(&student)
    
  • 适用场景:用于检索表中的任意一条记录,常用于测试或简化查询。

5. RawScan
  • 功能

    • Raw:执行原始 SQL 查询。
    • Scan:将原始 SQL 查询的结果扫描到 Go 变量中。
  • 用法

    var students []Student
    db.Raw("SELECT * FROM students WHERE age > ?", 18).Scan(&students)
    
  • 适用场景:用于执行复杂的原始 SQL 查询,特别是当 GORM 的链式调用不够灵活时。Scan 用于将查询结果填充到自定义结构体或切片中。

6. Model
  • 功能:用于指定模型类型,通常在查询链中用于指定操作的表。

  • 用法

    var students []Student
    db.Model(&Student{}).Where("age > ?", 18).Find(&students)
    
  • 适用场景:在需要在查询中指定模型时使用,比如在链式调用中切换模型。

7. Table
  • 功能:用于指定操作的表名,通常用于原始 SQL 查询。

  • 用法

    var students []Student
    db.Table("students").Where("age > ?", 18).Find(&students)
    
  • 适用场景:用于在查询中指定表名,特别是当表名不是结构体名称或当执行原始 SQL 查询时。

感觉和mybatis-plus差不多其中的链式查询

最后写一个动态sql执行

func GetStudents(name string, age int, gender string) ([]Student, error) {var students []Studentdb := db.Model(&Student{})if name != "" {db = db.Where("name = ?", name)}if age > 0 {db = db.Where("age = ?", age)}if gender != "" {db = db.Where("gender = ?", gender)}err := db.Find(&students).Errorreturn students, err
}

模型定义

和mybatis-plus的思路一样

一对多

可以采用聚合集合的方式

type User struct {ID       uint      `gorm:"size:4"`Name     string    `gorm:"size:8"`Articles []Article // 用户拥有的文章列表
}type Article struct {ID     uint   `gorm:"size:4"`Title  string `gorm:"size:16"`UserID uint   // 属于   这里的类型要和引用的外键类型一致,包括大小User   User   // 属于
}
关联外键
type User struct {ID       uint      `gorm:"size:4"`Name     string    `gorm:"size:8"`Articles []Article `gorm:"foreignKey:UID"` // 用户拥有的文章列表
}type Article struct {ID    uint   `gorm:"size:4"`Title string `gorm:"size:16"`UID   uint   // 属于User  User   `gorm:"foreignKey:UID"` // 属于
}

事务

java中可以通过@Trantial注解完成这个效果 gorm中可以通过手动和自动方式实现

手动实现

func CreateUserWithOrders(db *gorm.DB) error {return db.Transaction(func(tx *gorm.DB) error {// 创建用户user := User{Name: "John"}if err := tx.Create(&user).Error; err != nil {return err // 回滚事务}// 创建订单order := Order{UserID: user.ID, Amount: 100}if err := tx.Create(&order).Error; err != nil {return err // 回滚事务}// 如果一切正常,事务会自动提交return nil})
}

多表操作时候才transaction中处理 如果参数异常就返回 数据库进行回滚 也可以db.Begin() api方式

func CreateUserWithOrders(db *gorm.DB) error {tx := db.Begin()// 创建用户user := User{Name: "John"}if err := tx.Create(&user).Error; err != nil {tx.Rollback() // 回滚事务return err}// 创建订单order := Order{UserID: user.ID, Amount: 100}if err := tx.Create(&order).Error; err != nil {tx.Rollback() // 回滚事务return err}return tx.Commit().Error // 提交事务
}

这篇关于快速学习gorm 框架的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096628

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

GORM中Model和Table的区别及使用

《GORM中Model和Table的区别及使用》Model和Table是两种与数据库表交互的核心方法,但它们的用途和行为存在著差异,本文主要介绍了GORM中Model和Table的区别及使用,具有一... 目录1. Model 的作用与特点1.1 核心用途1.2 行为特点1.3 示例China编程代码2. Tab

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid

最新Spring Security实战教程之Spring Security安全框架指南

《最新SpringSecurity实战教程之SpringSecurity安全框架指南》SpringSecurity是Spring生态系统中的核心组件,提供认证、授权和防护机制,以保护应用免受各种安... 目录前言什么是Spring Security?同类框架对比Spring Security典型应用场景传统

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx