-
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: "[email protected]", Password: "123456"}
db.Create(&user)
在上面的代码中,创建一个User
类型的变量,并使用更新记录
go复制代码
db.Model(&user).Update("age", 30)
在上面的代码中,使用Update()
方法更新user
变量对应的记录中的年龄字段。
删除记录
go复制代码
db.Delete(&user)
-
go.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查询问题,通过合理地设计模型和使用预加载等技巧来优化查询效率。
-
go.gorm 增删改查DB时使用到哪些关键字,以及实例
Create
:创建一条记录。Save
:保存一条记录,如果记录存在则更新,否则创建新记录。Update
:更新符合条件的记录。Delete
:删除符合条件的记录。First
:查询符合条件的第一条记录。Last
:查询符合条件的最后一条记录。Find
:查询符合条件的所有记录。Where
:添加查询条件。Order
:添加排序规则。Limit
:设置查询结果集的上限。
Preload
:预先加载关联数据,避免N+1查询问题。Count
:统计符合条件的记录数量。Exec
:执行自定义SQL语句。Scan
:将查询结果映射到指定的结构体中。
- 创建一条记录
go复制代码
user := User{Name: "Tom", Age: 20}
db.Create(&user)
- 更新一条记录
go复制代码
db.Model(&User{}).Where("name = ?", "Tom").Update("age", 25)
- 删除一条记录
go复制代码
db.Delete(&User{}, "id = ?", 1)
- 根据条件查询记录
go复制代码
var user User
db.Where("name = ?", "Tom").First(&user)
- 查询所有记录
go复制代码
var users []User
db.Find(&users)
- 对查询结果集进行排序和分页处理
go复制代码
var users []User
db.Order("age desc").Limit(10).Offset(0).Find(&users)
通过上面的示例代码,可以看到如何使用GORM进行增删改查操作,并利用关键字来添加查询条件、排序规则和分页处理等功能,从而提升查询效率和数据管理能力。
除了上述示例中的常规使用方式外,还可以结合其他关键字和方法来进行更加灵活和复杂的操作。例如:
- 使用
Preload()
方法预先加载关联数据,避免N+1查询问题。
go复制代码
var users []User
db.Preload("Articles").Find(&users)
- 使用
Count()
方法统计符合条件的记录数量。
go复制代码
var count int64
db.Model(&User{}).Where("name = ?", "Tom").Count(&count)
- 使用
Exec()
方法执行自定义SQL语句。
go复制代码
db.Exec("UPDATE users SET age = ? WHERE name = ?", 30, "Tom")
- 使用
Scan()
方法将查询结果映射到指定的结构体中。
go复制代码
type UserAge struct {
Age int
}
var result UserAge
db.Model(&User{}).Select("AVG(age) as age").Scan(&result)
在实际应用中,我们可以根据具体的业务需求和数据模型设计,灵活地选取适合的关键字和方法来进行增删改查操作,从而实现高效的数据管理和查询
-
go.gorm 事务处理机制
- 开启事务
Begin()
方法开启一个新的事务,在该事务内执行的所有操作都将作为一个整体进行管理。
go复制代码
tx := db.Begin()
- 提交事务
Commit()
方法提交事务。
go复制代码
if err := tx.Commit().Error; err != nil {
// 事务提交失败
}
- 回滚事务
Rollback()
方法回滚事务,撤销所有已完成但未提交的操作。
go复制代码
if err := tx.Rollback().Error; err != nil {
// 事务回滚失败
}
- 事务嵌套
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 {
// 事务提交失败
}
- 事务处理函数
Transaction()
方法来封装事务处理函数,简化事务处理流程。该方法接受一个闭包函数作为参数,在该函数内执行需要进行事务管理的操作。
go复制代码
db.Transaction(func(tx *gorm.DB) error {
// 在tx事务内执行操作// ...return nil // 返回nil表示事务提交成功,返回非nil表示回滚事务
})
通过上面的示例代码,可以看到如何利用GORM提供的事务处理机制来实现代码的事务化管理,从而保证数据的完整性和一致性。
-
go.gorm 事务处理-隐式事务,显式事务
显式事务
显式事务是指在代码中显式地开启、提交和回滚事务。- 在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会自动回滚事务,撤销所有已完成但未提交的操作。
隐式事务
- 优点是编码简单,无需显式地管理事务的开启和提交等过程。
- 缺点是较难控制事务的边界,可能会导致不必要的数据库操作,影响执行效率。
-
gorm 中什么场景适合显示事务,什么场景适合隐式事务
显式事务
显式事务通常适用于以下场景:- 需要对多个数据表进行复杂操作时。因为显式事务能够更加精细地控制事务的边界,避免不必要的数据库操作。
- 当前操作与上下文相关性强,需要独立于其他操作单独处理时。例如,在一个Web请求中,处理完所有数据库操作后再提交事务,可以确保每个Web请求都是原子操作。
- 代码可读性要求高、易于维护时。显式事务可以更清晰地表达代码意图,便于后期维护。
隐式事务
隐式事务通常适用于以下场景:- 简单的增删改查操作。因为隐式事务能够提高代码的简洁性和可读性,减少不必要的代码量。
- 在一个事务内只需要处理一个操作时。使用隐式事务可以省去开启和提交事务的步骤,从而提高执行效率。
- 显式事务主要用于隐式事务主要用于但是,在具体应用中,我们需要根据实际情况选择适合的事务处理方式,以满足业务需求和代码优化的要求。
-
关于 gorm使用中 事务处理的最佳实践
- 显式事务优于隐式事务
- 严格控制事务的生命周期
- 避免事务嵌套
- 使用事务处理函数
Transaction()
方法来封装事务处理函数,简化事务处理流程。该方法接受一个闭包函数作为参数,在该函数内执行需要进行事务管理的操作。
go复制代码
db.Transaction(func(tx *gorm.DB) error {
// 在tx事务内执行操作
// ...return nil
// 返回nil表示事务提交成功,返回非nil表示回滚事务
})
- 错误处理与日志记录
log
库记录错误信息,并将错误信息和调用栈输出到日志文件中,方便后续排查和分析。
综上所述,GORM使用事务的最佳实践是:
- 选择合适的事务类型(显式事务或隐式事务)、
- 严格控制事务的生命周期、
- 避免事务嵌套、
- 使用事务处理函数、
- 正确处理和记录错误信息。
-
go.gorm 底层原理
go复制代码
type User struct {
ID uint `gorm:"primary_key"`
Name string `gorm:"unique_index"`
Age int
}
GORM会将该结构体映射为一个名为users
的表,包含三列id
、name
和age
,其中id
是主键列,name
是唯一索引列。
在进行数据的增删改查等操作时,
GORM会先将结构体转换为SQL语句,然后通过数据库驱动执行该SQL语句。
GORM支持多种数据库驱动,如MySQL、PostgreSQL、SQLite等,用户可以根据自己的需求选择不同的驱动。
GORM还提供了事务处理、预加载、查询条件构建、关联查询等高级功能,使得数据操作更加灵活和高效。
总的来说,-
gorm核心源码有哪些
gorm.DB
是GORM的核心结构体,它封装了与数据库交互的所有方法和属性。
gorm.Model
gorm.Model
是GORM提供的一个默认模型,它包含了一些常用的字段,例如id
、created_at
、updated_at
等,可以作为其他模型的基类使用。
gorm.Scope
是GORM的操作层,用于gorm.Expr
gorm.Expr
是GORM提供的一个辅助类型,用于构建SQL表达式和参数。它可以包装SQL字符串、函数调用、子查询等多种形式的表达式,并支持参数化输入,防止SQL注入攻击。
gorm.Migrator
gorm.Migrator
是GORM提供的迁移工具,用于创建、修改和删除数据库表。它支持自动检测模型变化和表结构变化,并提供了版本控制和回滚等功能。
gorm.Dialector
gorm.Dialector
是GORM提供的驱动抽象接口,用于支持不同的数据库驱动。它定义了一组通用的方法,包括数据类型映射、SQL语法解析、连接池管理等,从而使得GORM能够兼容多种数据库系统。
综上所述,GORM的核心源码包括gorm.DB
、gorm.Model
、gorm.Scope
、gorm.Expr
、gorm.Migrator
和gorm.Dialector
等模块。这些模块相互协作,实现了GORM的基本功能,包括数据映射、事务处理、查询条件构建、结果集解析、迁移工具等。
-
go.gorm 核心源码分析
gorm.DB
gorm.DB
是GORM的核心结构体,它封装了与数据库交互的���有方法和属性。其中包含以下核心功能:
- 连接池管理:
gorm.DB
在初始化时会创建一个连接池,用于缓存数据库连接,减少每次操作时创建连接的开销。 - 事务管理:
gorm.DB
支持基于函数回调的事务处理,用户可以通过Begin()
、Commit()
和Rollback()
等方法来控制事务的开启和关闭。 - 表映射:
gorm.DB
利用反射机制将Go结构体映射为数据库表,同时也支持自定义表名、列名、索引等属性。 - 查询条件构建:
gorm.DB
提供了一组链式调用API,使得用户可以方便快捷地构建复杂的查询条件。 - 结果集解析:
gorm.DB
使用反射机制将查询结果映射为Go对象,并支持多种关联查询、预加载等高级操作。
gorm.Model
gorm.Model
是GORM提供的一个默认模型,它包含了一些常用的字段,例如id
、created_at
、updated_at
等,可以作为其他模型的基类使用。gorm.Model
也可以通过自定义结构体来实现更加灵活的数据模型定义。
gorm.Scope
gorm.Scope
是GORM的操作层,用于执行SQL语句并将结果映射为Go对象。它包含以下核心功能:
- 基本操作:
gorm.Scope
封装了对单个模型的增删改查等基本操作,例如Create()
、Update()
、Delete()
、Find()
等。 - 高级操作:
gorm.Scope
支持事务处理、关联查询、预加载、分页查询等高级操作,可以满足各种业务需求。 - SQL构建:
gorm.Scope
利用sql.DB
和sql.Tx
提供的方法,将结构体或查询条件转换为SQL语句,并执行该语句获取结果。 - 结果解析:
gorm.Scope
使用反射机制将查询结果映射为Go对象,并支持多种关联查询、预加载等高级操作。
gorm.Expr
gorm.Expr
是GORM提供的一个辅助类型,用于构建SQL表达式和参数。它可以包装SQL字符串、函数调用、子查询等多种形式的表达式,并支持参数化输入,防止SQL注入攻击。
gorm.Migrator
gorm.Migrator
是GORM提供的迁移工具,用于创建、修改和删除数据库表。它支持自动检测模型变化和表结构变化,并提供了版本控制和回滚等功能。
gorm.Dialector
gorm.Dialector
是GORM提供的驱动抽象接口,用于支持不同的数据库驱动。它定义了一组通用的方法,包括数据类型映射、SQL语法解析、连接池管理等,从而使得GORM能够兼容多种数据库系统。
综上所述,GORM的核心源码包括gorm.DB
、gorm.Model
、gorm.Scope
、gorm.Expr
、gorm.Migrator
和gorm.Dialector
等模块。这些模块相互协作,实现了GORM的基本功能,包括数据映射、事务处理、查询条件构建、结果集解析、迁移工具等。
标签:事务,框架,GORM,db,查询,go,gorm
From: https://www.cnblogs.com/shoshana-kong/p/17728239.html