青训营go语言基础总结八:Gorm入门| 豆包MarsCode AI 刷题

189 阅读4分钟

1. 什么是Gorm

Gorm是一个用于Go语言的ORM库,它提供了丰富的API来简化与数据库的交互,支持主流的关系型数据库如MySQL、PostgreSQL、SQLite等。它通过数据库方言,屏蔽掉各个数据库的差异、利用反射获取结构体的字段和tag与数据库做映射,

特性

  1. 全功能 ORM
  2. 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  3. Create,Save,Update,Delete,Find 中钩子方法
  4. 支持 Preload、Joins 的预加载
  5. 事务,嵌套事务,Save Point,Rollback To Saved Point
  6. Context、预编译模式、DryRun 模式
  7. 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  8. SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  9. 复合主键,索引,约束
  10. Auto Migration
  11. 自定义 Logger
  12. 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  13. 每个特性都经过了测试的重重考验
  14. 开发者友好

2. 安装Gorm

首先需要安装Gorm及其数据库驱动,以MySQL为例:

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

3. 连接数据库

以下是如何连接MySQL数据库:

package main
import ( 
"gorm.io/driver/mysql" "gorm.io/gorm" "log"
) 
func main() { 
dsn := "username: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 { ‘log.Fatal(err) 
} 
log.Println("Database connected!") 
}

usernamepassword127.0.0.1dbname替换为自己实际的数据库连接信息。 数据表尽量用utf8mb4字符集,因为历史问题,mysql里面的utf8不是真正的utf8,utf8mb4才是真正的utf8字符集

4. 定义模型

例如我们要操作一个用户信息的表,可以先定义一个User模型:

type User struct { 
ID int64 `gorm:"primaryKey"` 
Name string 
Email string `gorm:"unique"` 
Age int 
CreatedAt time.Time 
UpdatedAt time.Time 
}

在 Go 语言程序中,一个 time.Time 类型的变量可以对应存储到 MySQL 的 DATETIME 或 TIMESTAMP 类型的字段中。 对于整型变量尽量采用合适的类型例如int64,不要用int

5. 自动迁移

使用Gorm的AutoMigrate函数可以自动创建或更新数据库表:

func main() {
// ... (前面的代码) 
db.AutoMigrate(&User{}) 
log.Println("Database migrated!") 
}

6. 创建记录

可以使用Create函数插入新的记录:

func main() { 
// ... (前面的代码) 
db.Create(&User{Name: "John Doe", Email: "john@example.com", Age: 25}) 
log.Println("User created!") 
}

我们还可以使用 Create() 创建多项记录:

users := []*User{     
{Name: "Jinzhu", Age: 18, Birthday: time.Now()},   
{Name: "Jackson", Age: 19, Birthday: time.Now()}, 
} 
result := db.Create(users) // pass a slice to insert multiple row  
result.Error        // returns error result.RowsAffected // returns inserted 
records count

创建记录并为指定字段赋值。

db.Select("Name", "Age", "CreatedAt").Create(&user) 
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775") 

7. 查询记录

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误

// 获取第一条记录(主键升序) 
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) 

如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user)Find方法可以接受struct和slice的数据。

8. 更新记录

使用SaveUpdates方法可以更新记录:

func main() { 
// ... (前面的代码) 
var user User db.First(&user, 1) 
user.Name = "Jane Doe" db.Save(&user) 
db.Model(&user).Update("Age", 30) 
db.Model(&user).Updates(User{Name: "Jane Doe", Age: 30}) 
log.Println("User updated!") 
}

gorm的几种更新方式:

1、Save 会保存所有的字段,即使字段是零值

db.Save(&updateUser)

2、update结合find或者where使用,更新单个列

db.Model(&TestUser{}).Where("id = ?", 2).Update("name", "hello")

3、updates更新多列,两种形式:Map & 结构体,结构体零值不参与更新

db.Model(&TestUser{}).Where("id = ?", 3).Updates(TestUser{Name: "hello11", Age: 18})

9. 删除记录

使用Delete方法可以删除记录:

func main() { 
// ... (前面的代码) 
var user User db.First(&user, 1) 
db.Delete(&user) 
log.Println("User deleted!") 
}

在项目实际开发过程中,一般都是软删除,不会直接物理删除的。

10. Gorm的坑

当使用零值进行查询时,零值并没有作为查询条件进行查询
更新时也有这样的问题,零值不更新

当使用结构作为条件查询时,GORM 只会查询非零值字段,更新也是如此。 当使用结构作为条件查询时,GORM 只会查询非零值字段,更新也是如此。