1. 什么是Gorm
Gorm是一个用于Go语言的ORM库,它提供了丰富的API来简化与数据库的交互,支持主流的关系型数据库如MySQL、PostgreSQL、SQLite等。它通过数据库方言,屏蔽掉各个数据库的差异、利用反射获取结构体的字段和tag与数据库做映射,
特性
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持 Preload、Joins 的预加载
- 事务,嵌套事务,Save Point,Rollback To Saved Point
- Context、预编译模式、DryRun 模式
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
- 复合主键,索引,约束
- Auto Migration
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
- 每个特性都经过了测试的重重考验
- 开发者友好
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!")
}
username、password、127.0.0.1、dbname替换为自己实际的数据库连接信息。
数据表尽量用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 提供了 First、Take、Last 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 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. 更新记录
使用Save或Updates方法可以更新记录:
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 只会查询非零值字段,更新也是如此。