这是我参与「第五届青训营」伴学笔记创作活动的第 6 天
1. 概述
我将主要介绍如下知识点:
- Gorm 的基本使用
- Gorm 的增删改查
2. Gorm 的基本使用
2.1 导入 Gorm 和 MySQL 数据驱动
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
2.2 定义结构体
-
也就是
gorm model,对应数据库里的一张表 -
可以使用
default标签为字段定义默认值如:Age int64 `gorm:"default:18"`
type Product struct {
Code string
Price uint
}
2.3 为 model 定义表名
- gorm 提供了 TableName() 这个接口
func (p Product) TableName() string {
return "product" // 返回的字符串即表名
}
2.4 快速入门
关于什么是 dsn,感兴趣可以看:github.com/go-sql-driv…
func main() {
// 连接数据库(需要传递一个 dsn)
db, err := gorm.Open(
mysql.Open("user:pass@(127.0.0.1:3306)/dname?charset=utf8mb4&parseTime=True&loc=Local"),
&gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 创建数据 Create() 方法支持创建一条(传递对象)和多条数据(传递数组)
db.Create(&Product{Code: "D42", Price: 100})
// 查询数据 先声明一个结构体, 然后使用 First() 方法(注意是传递指针)
var product Product
db.First(&product, 1) // 根据整型主键查找
db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
// 更新数据 - 用 Update() 方法将 product 的 price 更新为 200
db.Model(&product).Update("Price", 200)
// 更新数据 - 用 Updates() 方法更新多个字段
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}) // 传递 map 可以更新零值
// 删除数据
db.Delete(&product, 1)
}
2.5 Gorm 的默认约定
-
Gorm 使用名为
ID 的字段作为主键 -
使用结构体名的
蛇形命名作为表名如:对于结构体
User,根据约定,其表名为users -
字段名的蛇形作为列名
-
使用 CreatedAt、UpdatedAt 字段作为创建、更新时间
3. GORM 支持的数据库
GORM 目前支持: MySQL,SQL Server,PostgreSQL,SQLite
- GORM 通过驱动来连接数据库,如果需要连接其它类型的数据库,可以复用/自行开发驱动
4. GORM 的 crud
4.1 创建数据
-
如下是定义的结构体
type Product struct { ID uint `gorm:"primarykey"` Code string `gorm:"column: code"` Price uint `gorm:"column: user_id"` } -
创建一条数据
注意:gorm 是链式调用,使用 Creat() 后会返回一个gorm 对象,可以通过返回的对象获取 error
p := &Product{Code: "D42"} res := db.Create(p) // 因为 gorm 是链式调用, 使用 Creat() 后会返回一个gorm对象 fmt.Println(res.Error) // 获取 err fmt.Println(p.ID) // 返回插入数据的主键 -
创建多条数据
需要去传递一个 list 结构体
products := []*Product{{Code: "D41"}, {Code: "D42"}, {Code: "D43"}} res = db.Create(products) // 批量创建数据 fmt.Println(res.Error) // 获取 err for _, p := range products { fmt.Println(p.ID) }
4.2 查询数据
-
如下是定义的结构体
type User struct { ID int64 Name string `gorm:"default:galeone"` Age int64 `gorm:"default:18"` } -
查询第一条数据
使用 First 时,查询不到数据则返回 ErrRecordNotFound// 获取第一条记录(主键升序) u := &User{} db.First(u) // SELECT * FROM users ORDER BY id LIMIT 1; -
条件查询
使用 Find 查询多条数据,查询不到数据不会返回错误// 查询多条数据 users := make([]*User, 0) result := db.Where("age > 10").Find(&users) // SELECT * FROM users where age > 10 fmt.Println(result.RowsAffected) // 返回找到的记录数, 相当于 `len(users)` fmt.Println(result.Error) // return error // IN => SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2'); db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users) // LIKE => SELECT * FROM users WHERE name LIKE '%jin%'; db.Where("name LIKE ?", "%jin%").Find(&users) // AND => SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22; db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users) -
使用结构体或者map作为查询条件(较少用)
当使用结构体作为条件查询时,GORM 只会查询非零值字段;若字段为 0、”“、false 或其它零值,使用 Map 来构建查询条件// SELECT * FROM users WHERE name = "jinzhu"; db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users) // SELECT * FROM users WHERE name = "jinzhu" AND age = 0; db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
4.3 更新数据
-
更新单个列
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE age > 18 db.Model(&User{ID: 111}).Where("age > ?", 18).Update("name", "hello") -
更新多个列
根据 `struct` 更新属性,只会更新非零值的字段
// UPDATE users SET name='hello', age=18, updated_at='2013-11-17 21:34:10' WHERE id = 111; db.Model(&User{ID: 111}).Updates(User{Name: "hello", Age: 18}) -
根据 `map` 更新属性
// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id = 111; db.Model(&User{ID: 111}).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false}) -
更新选定字段
下面这段代码中虽然 map 中有多个键值对,但是其实只会更新 Select() 选定的 name 字段
// UPDATE users SET name='hello' WHERE id=111; db.Model(&User{ID: 111}).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
4.4 删除数据
物理删除
// DELETE FROM users WHERE id = 10;
db.Delete(&User{}, 10)
// DELETE FROM users WHERE id IN (1,2,3);
db.Delete(&User{}, []int{1, 2, 3})
// DELETE FROM users WHERE name LIKE "%jinzhu%";
db.Where("name LIKE ?", "%jinzhu%").Delete(User{})
// DELETE FROM users WHERE name LIKE "%jinzhu%";
db.Delete(User{}, "name LIKE ?", "%jinzhu%")
软删除
GORM 提供了
gorm.DeletedAt用于帮助用户实现软删拥有软删能力的 Model 调用 Delete 时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt 置为当前时间,并且你不能再通过正常的查询方法找到该记录
使用
Unscoped可以查询到被软删的数据
-
拥有软删能力的 model 定义如下:
type User struct { ID int64 Name string `gorm:"default:galeone"` Age int64 `gorm:"default:18"` Deleted gorm.DeletedAt } -
删除一条
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111; u := User{ID: 111} db.Delete(&u) -
批量删除
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20; db.Where("age = ?", 20).Delete(&User{}) users := make([]*User, 0) // 在查询时会忽略被软删的记录 // SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL; db.Where("age = 20").Find(&users) // 在查询时不会忽略被软删的记录 // SELECT * FROM users WHERE age = 20; db.Unscoped().Where("age = 20").Find(&users)
5. 总结
GORM 是 Go 语言中一款性能极好的 ORM 库,对开发人员相对是比较友好的。
参考:
- 字节内部课:Go 框架三件套详解
- gorm.cn/docs/#Insta…