go之gorm 框架

发布时间 2023-09-25 16:39:04作者: 白露~
 
 
  1. go.gorm 使用

 
GORM是一个Go语言的ORM库,用于简化数据库操作。它支持MySQL、PostgreSQL、SQLite和SQL Server等多种数据库,并提供了丰富的API,使得我们可以很方便地进行增删改查等操作。
本文将介绍如何在GO中使用gorm,并提供一些示例代码。

安装gorm

在开始使用gorm之前,需要先安装它。可以使用以下命令进行安装:
复制代码
go get -u github.com/jinzhu/gorm

连接数据库

使用gorm连接数据库非常简单,只需指定数据库类型和连接字符串即可。下面是连接MySQL数据库的示例代码:
go复制代码
import (
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
    db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 使用db进行数据库操作...
}
其中,Open()方法的第一个参数指定数据库类型,第二个参数是连接字符串。在连接字符串中,需要指定用户名、密码、主机地址、端口号、数据库名以及字符集等信息。

创建模型

在使用gorm进行数据库操作之前,需要先定义模型(Model)。模型是一个结构体,用于描述数据库表中的一条记录。下面是一个用户模型的示例代码:
go复制代码
type User struct {
    ID       uint   `gorm:"primary_key"`
    Name     string `gorm:"size:32;unique_index"`
    Age      int
    Email    string `gorm:"size:64;unique_index"`
    Password string `gorm:"size:64"`
    CreatedAt time.Time
    UpdatedAt time.Time
}
在上面的代码中,定义了一个名为User的结构体,包含了ID、Name、Age、Email、Password、CreatedAt和UpdatedAt等字段。通过在这些字段上添加gorm的标签(Tag),可以设置它们在数据库中的约束条件、索引等属性。

创建表

使用gorm创建表非常简单,只需调用AutoMigrate()方法即可。下面是创建用户表的示例代码:
go复制代码
func main() {
    db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 自动迁移模型,创建用户表
    db.AutoMigrate(&User{})
}
在上面的代码中,调用了AutoMigrate()方法并传入了一个User类型的变量,这样就会自动根据该模型创建对应的数据库表。

增删改查

使用gorm进行增删改查操作也非常方便,下面是一些常见的数据库操作示例:

查询所有记录

go复制代码
var users []User
db.Find(&users)
在上面的代码中,使用条件查询
go复制代码
var user User
db.Where("name = ?", "Tom").First(&user)
在上面的代码中,使用Where()方法添加查询条件,并通过新增记录
go复制代码
user := User{Name: "Jack", Age: 20, Email: "jack@example.com", Password: "123456"}
db.Create(&user)
在上面的代码中,创建一个User类型的变量,并使用更新记录
go复制代码
db.Model(&user).Update("age", 30)
在上面的代码中,使用Update()方法更新user变量对应的记录中的年龄字段。

删除记录

go复制代码
db.Delete(&user)
 
 
  1. go.gorm 关联查询如何操作

GORM提供了丰富的API,可以轻松进行关联查询。在GORM中,关联查询可以分为两种类型:一对多关联和多对多关联。下面我们将介绍如何使用GORM进行这两种类型的关联查询。

一对多关联

一对多关联是指一个模型(Model)关联多个子模型的情况。例如,在一个博客系统中,一个用户可以有多篇文章,那么用户模型和文章模型之间就存在一对多关联。
在GORM中,使用HasMany()方法可以定义一对多关联。该方法接受两个参数,第一个参数是需要关联的子模型,第二个参数是外键字段名。
下面是一个示例代码:
go复制代码
type User struct {
    ID       uint   `gorm:"primary_key"`
    Name     string `gorm:"size:32;unique_index"`
    Age      int
    Articles []Article // 一对多关联
}

type Article struct {
    ID        uint   `gorm:"primary_key"`
    Title     string `gorm:"size:64"`
    Content   string `gorm:"size:65535"`
    UserID    uint   `gorm:"index"` // 外键
    CreatedAt time.Time
    UpdatedAt time.Time
}

func main() {
    db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 自动迁移模型
    db.AutoMigrate(&User{}, &Article{})

    // 创建一条用户记录和多条文章记录
    user := User{Name: "Tom", Age: 20}
    article1 := Article{Title: "Title1", Content: "Content1", UserID: user.ID}
    article2 := Article{Title: "Title2", Content: "Content2", UserID: user.ID}
    db.Create(&user)
    db.Create(&article1)
    db.Create(&article2)

    // 查询用户及其所有文章var u User
    db.Preload("Articles").First(&u)
    fmt.Println(u.Name) // 输出"Tom"
    fmt.Println(len(u.Articles)) // 输出"2"
}
在上面的代码中,定义了一个User类型和一个Article类型。在User类型中,通过添加[]Article字段来定义与Article类型的一对多关联。在Article类型中,通过添加UserID字段来表示该文章所属的用户ID,并添加了相应的外键约束。在创建记录和查询记录时,我们也可以看到如何利用这些关联信息进行操作和查询。
 

多对多关联

多对多关联是指两个模型间相互关联的情况,例如,在一个音乐平台中,一个歌曲可以属于多个歌单,而一个歌单也可以包含多个歌曲,那么歌曲模型和歌单模型之间就存在多对多关联。
在GORM中,使用ManyToMany()方法可以定义多对多关联。该方法接受三个参数,第一个参数是需要关联的模型,第二个参数是关联表名,第三个参数是外键字段名。
下面是一个示例代码:
go复制代码
type Song struct {
    ID      uint   `gorm:"primary_key"`
    Title   string `gorm:"size:64"`
    Artists []Artist `gorm:"many2many:song_artists"` // 多对多关联
}

type Artist struct {
    ID    uint   `gorm:"primary_key"`
    Name  string `gorm:"size:32"`
    Songs []Song `gorm:"many2many:song_artists"` // 多对多关联
}

func main() {
    db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 自动迁移模型
    db.AutoMigrate(&Song{}, &Artist{})

    // 创建两个歌手和多首歌曲
    artist1 := Artist{Name: "Jay Chou"}
    artist2 := Artist{Name: "Taylor Swift"}
    song1 := Song{Title: "Song1", Artists: []Artist{artist1, artist2}}
    song2 := Song{Title: "Song2", Artists: []Artist{artist1}}
    db.Create(&song1)
    db.Create(&song2)

    // 查询歌曲及其所有艺术家var s Song
    db.Preload("Artists").First(&s)
    fmt.Println(s.Title) // 输出"Song1"
    fmt.Println(len(s.Artists)) // 输出"2"
}
在上面的代码中,我们定义了一个Song类型和一个Artist类型,为它们建立多对多关联,并创建了两个歌手和多首歌曲。在查询歌曲及其所有艺术家时,通过调用Preload()方法预先加载关联数据,从而避免了N+1查询问题。
 

N+1查询问题

是指在进行ORM查询时,如果将多表关联的数据分开查询会导致额外的大量查询操作,从而降低了查询效率。
例如,在一个博客系统中,需要查询所有用户及其发表的文章。如果分两次查询,第一次查询所有用户信息,第二次查询每个用户的文章信息,则需要执行n+1次查询(n为用户数量),这将导致数据库负担增大,查询效率下降。而如果使用GORM的Preload()方法,可以预先加载所有用户的文章信息,只需执行2次查询,避免了额外的查询操作,提升了查询效率。
因此,在进行ORM查询时,我们需要注意避免N+1查询问题,通过合理地设计模型和使用预加载等技巧来优化查询效率。
 
  1. go.gorm 增删改查DB时使用到哪些关键字,以及实例

在GORM中,进行增删改查DB时可以使用以下关键字:
  • Create:创建一条记录。
  • Save:保存一条记录,如果记录存在则更新,否则创建新记录。
  • Update:更新符合条件的记录。
  • Delete:删除符合条件的记录。
  • First:查询符合条件的第一条记录。
  • Last:查询符合条件的最后一条记录。
  • Find:查询符合条件的所有记录。
  • Where:添加查询条件。
  • Order:添加排序规则。
  • Limit:设置查询结果集的上限。
此外还可以结合其他关键字和方法来进行更加灵活和复杂的操作
  • Preload:预先加载关联数据,避免N+1查询问题。
  • Count:统计符合条件的记录数量。
  • Exec:执行自定义SQL语句。
  • Scan:将查询结果映射到指定的结构体中。
下面是一些使用GORM进行增删改查操作的示例代码:
  1. 创建一条记录
go复制代码
user := User{Name: "Tom", Age: 20}
db.Create(&user)
  1. 更新一条记录
go复制代码
db.Model(&User{}).Where("name = ?", "Tom").Update("age", 25)
  1. 删除一条记录
go复制代码
db.Delete(&User{}, "id = ?", 1)
  1. 根据条件查询记录
go复制代码
var user User
db.Where("name = ?", "Tom").First(&user)
  1. 查询所有记录
go复制代码
var users []User
db.Find(&users)
  1. 对查询结果集进行排序和分页处理
go复制代码
var users []User
db.Order("age desc").Limit(10).Offset(0).Find(&users)
通过上面的示例代码,可以看到如何使用GORM进行增删改查操作,并利用关键字来添加查询条件、排序规则和分页处理等功能,从而提升查询效率和数据管理能力。
除了上述示例中的常规使用方式外,还可以结合其他关键字和方法来进行更加灵活和复杂的操作。例如:
  1. 使用Preload()方法预先加载关联数据,避免N+1查询问题。
go复制代码
var users []User
db.Preload("Articles").Find(&users)
  1. 使用Count()方法统计符合条件的记录数量。
go复制代码
var count int64
db.Model(&User{}).Where("name = ?", "Tom").Count(&count)
  1. 使用Exec()方法执行自定义SQL语句。
go复制代码
db.Exec("UPDATE users SET age = ? WHERE name = ?", 30, "Tom")
  1. 使用Scan()方法将查询结果映射到指定的结构体中。
go复制代码
type UserAge struct {
    Age int
}

var result UserAge
db.Model(&User{}).Select("AVG(age) as age").Scan(&result)
在实际应用中,我们可以根据具体的业务需求和数据模型设计,灵活地选取适合的关键字和方法来进行增删改查操作,从而实现高效的数据管理和查询
 
 
  1. go.gorm 事务处理机制

在GORM中,事务(Transaction)是指一组数据库操作,它们要么全部成功执行,要么全部回滚。当多个用户同时对同一数据进行操作时,使用事务可以避免并发冲突和数据丢失等问题。
以下是GORM中常用的事务处理机制:
  1. 开启事务
通过调用Begin()方法开启一个新的事务,在该事务内执行的所有操作都将作为一个整体进行管理。
go复制代码
tx := db.Begin()
  1. 提交事务
当事务内的所有操作都成功完成后,调用Commit()方法提交事务。
go复制代码
if err := tx.Commit().Error; err != nil {
    // 事务提交失败
}
  1. 回滚事务
当事务内的任何操作出现错误或异常情况时,调用Rollback()方法回滚事务,撤销所有已完成但未提交的操作。
go复制代码
if err := tx.Rollback().Error; err != nil {
    // 事务回滚失败
}
  1. 事务嵌套
在GORM中,支持嵌套事务,也就是在一个事务内开启另一个事务。这样做可以更加灵活地控制事务的边界,从而提高代码可维护性和可读性。
go复制代码
tx1 := db.Begin()
// 在tx1事务内开始tx2事务
tx2 := tx1.Begin()

// 执行tx1事务内的操作// ...// 提交tx2事务if err := tx2.Commit().Error; err != nil {
    // 事务提交失败
}
// 提交tx1事务if err := tx1.Commit().Error; err != nil {
    // 事务提交失败
}
  1. 事务处理函数
GORM还提供了Transaction()方法来封装事务处理函数,简化事务处理流程。该方法接受一个闭包函数作为参数,在该函数内执行需要进行事务管理的操作。
go复制代码
db.Transaction(func(tx *gorm.DB) error {
    // 在tx事务内执行操作// ...return nil // 返回nil表示事务提交成功,返回非nil表示回滚事务
})
通过上面的示例代码,可以看到如何利用GORM提供的事务处理机制来实现代码的事务化管理,从而保证数据的完整性和一致性。
 
  1. go.gorm 事务处理-隐式事务,显式事务

在GORM中,事务可以分为显式事务(Explicit Transaction)和隐式事务(Implicit Transaction)。

显式事务

显式事务是指在代码中显式地开启、提交和回滚事务。
  • 在GORM中,我们可以通过调用Begin()方法开启一个新的事务,
  • 然后在该事务内执行需要进行事务管理的操作,最后再调用Commit()Rollback()方法提交或回滚事务。
以下是一个使用显式事务的示例代码:
go复制代码
// 开始一个新的事务
tx := db.Begin()

// 在事务内执行操作if err := tx.Create(&User{Name: "Tom", Age: 20}).Error; err != nil {
    // 操作出错,回滚事务
    tx.Rollback()
}

// 提交事务if err := tx.Commit().Error; err != nil {
    // 事务提交失败
}
在这个示例中,我们首先调用Begin()方法开启一个新的事务,然后在事务内执行创建用户记录的操作。如果操作成功,则调用Commit()方法提交事务;如果操作出错,则调用Rollback()方法回滚事务,撤销所有已完成但未提交的操作。
显式事务
  • 优点是可以更加精细地控制事务的边界,可以减少不必要的数据库操作,从而提高执行效率。
  • 缺点是但是,它也需要手动管理事务的开启、提交和回滚等过程,代码相对比较复杂。

隐式事务

隐式事务是指在进行增删改查操作时自动开启、提交和回滚事务。GORM默认情况下就是采用隐式事务的方式,开发者不需要手动处理事务的开启和提交等过程。
以下是一个使用隐式事务的示例代码:
go复制代码
// 在默认的隐式事务内创建用户记录
if err := db.Create(&User{Name: "Tom", Age: 20}).Error; err != nil {
    // 操作出错,事务自动回滚
}
在这个示例中,我们没有手动开启和提交事务,而是直接使用Create()方法创建了一个新的用户记录。当操作出错时,GORM会自动回滚事务,撤销所有已完成但未提交的操作。
隐式事务
  • 优点是编码简单,无需显式地管理事务的开启和提交等过程。
  • 缺点是较难控制事务的边界,可能会导致不必要的数据库操作,影响执行效率。
因此,在实际应用中,我们需要根据具体的业务场景和数据操作需求,选择适合的事务处理方式。显式事务通常适用于需要对多个数据表进行复杂操作的场景,能够提高事务的执行效率和数据一致性;而隐式事务则适用于简单的增删改查操作,能够提高代码的简洁性与可读性。
 
  1. gorm 中什么场景适合显示事务,什么场景适合隐式事务

在GORM中,显式事务和隐式事务各有适用的场景。

显式事务

显式事务通常适用于以下场景:
  1. 需要对多个数据表进行复杂操作时。因为显式事务能够更加精细地控制事务的边界,避免不必要的数据库操作。
  2. 当前操作与上下文相关性强,需要独立于其他操作单独处理时。例如,在一个Web请求中,处理完所有数据库操作后再提交事务,可以确保每个Web请求都是原子操作。
  3. 代码可读性要求高、易于维护时。显式事务可以更清晰地表达代码意图,便于后期维护。

隐式事务

隐式事务通常适用于以下场景:
  1. 简单的增删改查操作。因为隐式事务能够提高代码的简洁性和可读性,减少不必要的代码量。
  2. 在一个事务内只需要处理一个操作时。使用隐式事务可以省去开启和提交事务的步骤,从而提高执行效率。
总的来说,
  • 显式事务主要用于隐式事务主要用于但是,在具体应用中,我们需要根据实际情况选择适合的事务处理方式,以满足业务需求和代码优化的要求。
  1. 关于 gorm使用中 事务处理的最佳实践

在GORM中,事务(Transaction)是指一组数据库操作,它们要么全部成功执行,要么全部回滚。当多个用户同时对同一数据进行操作时,使用事务可以避免并发冲突和数据丢失等问题。以下是GORM中使用事务的最佳实践:
  1. 显式事务优于隐式事务
显式事务通常会比隐式事务更加灵活和高效。
因为显式事务能够更加精细地控制事务的边界,避免不必要的数据库操作。
  1. 严格控制事务的生命周期
事务应该尽可能地短暂,及早提交或回滚。每个事务应该负责完成一个或多个相关联的操作,而不应该把所有的操作都放在同一个事务内。
  1. 避免事务嵌套
虽然GORM支持事务嵌套,但是在实际应用中,应该尽量避免使用事务嵌套。因为事务嵌套会增加代码的复杂度,降低代码的可读性和可维护性。
  1. 使用事务处理函数
GORM提供了Transaction()方法来封装事务处理函数,简化事务处理流程。该方法接受一个闭包函数作为参数,在该函数内执行需要进行事务管理的操作。
go复制代码
db.Transaction(func(tx *gorm.DB) error {
    // 在tx事务内执行操作
    // ...return nil 
    // 返回nil表示事务提交成功,返回非nil表示回滚事务
})
  1. 错误处理与日志记录
在事务处理过程中,可能会出现各种错误,例如数据库连接失败、事务提交失败等。为了防止这些错误导致程序崩溃,我们需要对错误进行处理和记录。建议使用log库记录错误信息,并将错误信息和调用栈输出到日志文件中,方便后续排查和分析。
综上所述GORM使用事务的最佳实践是:
  • 选择合适的事务类型(显式事务或隐式事务)、
  • 严格控制事务的生命周期、
  • 避免事务嵌套、
  • 使用事务处理函数、
  • 正确处理和记录错误信息。
这些最佳实践能够帮助我们编写出更加安全、高效和健壮的代码。
 
  1. go.gorm 底层原理

GORM是Go语言中一种基于结构体(Struct)的ORM库,能够将结构体映射为数据库表,并提供了丰富的API来进行数据的增删改查等操作。下面我们来简要介绍一下GORM的底层原理。
在GORM中,每个模型都对应着一个表,而每个字段则对应着表中的一列。GORM使用反射机制来将结构体映射成为数据库表,并根据标签(Tag)来配置表名、列名、索引等属性。例如,以下是一个User结构体:
go复制代码
type User struct {
    ID   uint   `gorm:"primary_key"`
    Name string `gorm:"unique_index"`
    Age  int
}
GORM会将该结构体映射为一个名为users的表,包含三列idnameage,其中id是主键列,name是唯一索引列。
 
在进行数据的增删改查等操作时,
GORM会先将结构体转换为SQL语句,然后通过数据库驱动执行该SQL语句。
GORM支持多种数据库驱动,如MySQL、PostgreSQL、SQLite等,用户可以根据自己的需求选择不同的驱动。
GORM还提供了事务处理、预加载、查询条件构建、关联查询等高级功能,使得数据操作更加灵活和高效。
 
总的来说,
  1. gorm核心源码有哪些

GORM是基于Go语言标准库database/sql接口实现的ORM框架,主要包含以下核心源码:
  1. gorm.DB是GORM的核心结构体,它封装了与数据库交互的所有方法和属性。
其中包含了gorm.Model
gorm.Model是GORM提供的一个默认模型,它包含了一些常用的字段,例如idcreated_atupdated_at等,可以作为其他模型的基类使用。
  1. gorm.Scope是GORM的操作层,用于gorm.Expr
gorm.Expr是GORM提供的一个辅助类型,用于构建SQL表达式和参数。它可以包装SQL字符串、函数调用、子查询等多种形式的表达式,并支持参数化输入,防止SQL注入攻击。
  1. gorm.Migrator
gorm.Migrator是GORM提供的迁移工具,用于创建、修改和删除数据库表。它支持自动检测模型变化和表结构变化,并提供了版本控制和回滚等功能。
  1. gorm.Dialector
gorm.Dialector是GORM提供的驱动抽象接口,用于支持不同的数据库驱动。它定义了一组通用的方法,包括数据类型映射、SQL语法解析、连接池管理等,从而使得GORM能够兼容多种数据库系统。
综上所述,GORM的核心源码包括gorm.DBgorm.Modelgorm.Scopegorm.Exprgorm.Migratorgorm.Dialector等模块。这些模块相互协作,实现了GORM的基本功能,包括数据映射、事务处理、查询条件构建、结果集解析、迁移工具等。
  1. go.gorm 核心源码分析

 
GORM中核心源码进行分析:
  1. gorm.DB
gorm.DB是GORM的核心结构体,它封装了与数据库交互的���有方法和属性。其中包含以下核心功能:
  • 连接池管理:gorm.DB在初始化时会创建一个连接池,用于缓存数据库连接,减少每次操作时创建连接的开销。
  • 事务管理:gorm.DB支持基于函数回调的事务处理,用户可以通过Begin()Commit()Rollback()等方法来控制事务的开启和关闭。
  • 表映射:gorm.DB利用反射机制将Go结构体映射为数据库表,同时也支持自定义表名、列名、索引等属性。
  • 查询条件构建:gorm.DB提供了一组链式调用API,使得用户可以方便快捷地构建复杂的查询条件。
  • 结果集解析:gorm.DB使用反射机制将查询结果映射为Go对象,并支持多种关联查询、预加载等高级操作。
  1. gorm.Model
gorm.Model是GORM提供的一个默认模型,它包含了一些常用的字段,例如idcreated_atupdated_at等,可以作为其他模型的基类使用。gorm.Model也可以通过自定义结构体来实现更加灵活的数据模型定义。
  1. gorm.Scope
gorm.Scope是GORM的操作层,用于执行SQL语句并将结果映射为Go对象。它包含以下核心功能:
  • 基本操作:gorm.Scope封装了对单个模型的增删改查等基本操作,例如Create()Update()Delete()Find()等。
  • 高级操作:gorm.Scope支持事务处理、关联查询、预加载、分页查询等高级操作,可以满足各种业务需求。
  • SQL构建:gorm.Scope利用sql.DBsql.Tx提供的方法,将结构体或查询条件转换为SQL语句,并执行该语句获取结果。
  • 结果解析:gorm.Scope使用反射机制将查询结果映射为Go对象,并支持多种关联查询、预加载等高级操作。
  1. gorm.Expr
gorm.Expr是GORM提供的一个辅助类型,用于构建SQL表达式和参数。它可以包装SQL字符串、函数调用、子查询等多种形式的表达式,并支持参数化输入,防止SQL注入攻击。
  1. gorm.Migrator
gorm.Migrator是GORM提供的迁移工具,用于创建、修改和删除数据库表。它支持自动检测模型变化和表结构变化,并提供了版本控制和回滚等功能。
  1. gorm.Dialector
gorm.Dialector是GORM提供的驱动抽象接口,用于支持不同的数据库驱动。它定义了一组通用的方法,包括数据类型映射、SQL语法解析、连接池管理等,从而使得GORM能够兼容多种数据库系统。
综上所述,GORM的核心源码包括gorm.DBgorm.Modelgorm.Scopegorm.Exprgorm.Migratorgorm.Dialector等模块。这些模块相互协作,实现了GORM的基本功能,包括数据映射、事务处理、查询条件构建、结果集解析、迁移工具等。