Gorm
引入
- 安装
go get -u gorm.io——导入gormgo get -u gorm.io/driver/mysql ——导入mysql引擎
- 创建数据库、表及设定好属性
CREATE DATABASE dbgorm
CREATE TABLE products(
`code` VARCHAR(50),
price FLOAT)
- 导入依赖包
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
- 设定操作的结构体(表的映射对象,表是复数如products,结构体单数Product)
type Product struct {
Code string
Price float32
}
- 为结构体定义表名(可有可无)
func (p Product) TableName() string{
return "product"
}
- 连接数据库
dsn := "root:ann@tcp(127.0.0.1:3306)/dbgorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
- 创建数据
//创建一条记录
db.Create(&Product{Code: "D42", Price: 100}) //方式一
p := &Product{Code: "D41", Price: 100}
res := db.Create(p) //方式二
//创建多条
products := []*Product{{Code: "D43", Price: 100}, {Code: "D44", Price: 100}}
db.Create(products)
- 如何使用 Upsert ——使用
clause.OnConflict处理数据冲突(以创建单条方式二为例)
db.Clauses(clause.OnConflict{DoNothing: true}).Create(&p)
- 如何使用默认值——通过 default 标签为字段定义默认值(在定义model时使用)
name string gorm:"default:ann"``
- 查询数据
//查询第一个,并显示
p := Product{}
result := db.First(&p)//排序第一个
fmt.Println(p)
//查询多个,并显示受影响行数
//指定查询条件
products := make([]*Product, 0)
result = db.Where("code IN ?", []string{"D42", "D41"}).Find(&products) //元组范围查询
result = db.Where("price >= 100").Find(&products) //范围查询
result = db.Where("code LIKE ?", "D4%").Find(&products) //模糊查询
result = db.Where("code = ? AND price >= ?", "D42", 100).Find(&products) //明确查询
//指定查询的对象
result = db.Where(&Product{Code: "D41", Price: 0}).Find(&products) //结构体(0/false的字段会被忽略)
result = db.Where(map[string]interface{}{"Code": "D41", "Price": 100}).Find(&products) //map
fmt.Println(result.RowsAffected)
- 使用
First时,需要注意查询不到数据会返回 ErrRecordNotFound - 使用
Find查询多条语句,查询不到数据不会返回错误 - 使用结构体作为查询条件时,GORM只会查询非零值字段(即字段值为0/false等,该字段不会用于构建查询条件,使用Map来构建查询条件)
- 更新数据
- 满足条件的单列全都改变(model指定数据库,where指定更新的范围,update指定更新内容)
- 如果
db.Model(&Product{id: "D42"})里面是主键,则相当于加了where id ="D42",如果里面不是主键,则必须要加where子句作为查询条件
//修改单列(update)
db.Model(&Product{Code: "D42"}).Where("price >= 100").Update("price", 200)
db.Model(&p).Where("code = ?", "D42").Update("price", 700) //单列
//修改多列(updates)
db.Model(&p).Where("code = ?", "D44").Updates(Product{Code: "D40", Price: 500}) //多列
//根据`map`更新属性(Updates)
db.Model(&p).Where("code = ?", "D41").Updates(map[string]interface{}{"Code": "D41", "Price": 700})
db.Model(&p).Where("code = ?", "D45").Select("code").Updates(map[string]interface{}{"Code": "D43", "Price": 800})
- 使用Struct更新时,只会更新非零值,如果需要更新零值可以使用Map更新或使用Select选择字段
- 删除数据
//物理删除
//用主键删除
db.Delete(&p,1)
db.Delete(&Product{},2)
//查询删除
db.Delete(Product{}, "code = ?", "D40")
db.Where("code = ?", "D43").Delete(Product{})
//软删除(结构体中定义Deleted gorm.DeletedAt)
p := Product{Code: "D42", Price: 100}
db.Delete(&p) //删一条
db.Where("code = ?", "D41").Delete(&Product{})//批量删除
//查询(普通查询不行)
products := make([]*Product, 0)
db.Unscoped().Where("code = ?", "D41").Find(&products)
- GORM 提供了gorm.DeletedAt用于帮助用户实现软删除,在model结构体中定义
Deleted gorm.DeletedAt - 拥有软删除能力的Model调用Delete时,记录不会被从数据库中真正删除,但GORM会将DeletedAt置为当前时间,并且你不能再通过正常的查询方法找到该记录
- 使用Unscoped可以查询到被软删的数据
- 默认约定
- Gorm 使用名为 ID 的字段作为主键
- Gorm 使用结构体的蛇形复数(小写+下划线+复数)Product——>products
- 字段名的蛇形作为列名
- 使用
CreatedAt、UpdatedAt字段作为创建、更新时间 - 支持的数据库(根据数据库的选择决定连接时 dsn格式)
- MySQL
- SQLServer
- PostgreSQL
- SQLite
操作详解
- 事务
- GORM提供了Begin、Commit、Rollback方法用于使用事务
tx := db.Begin()//开始事务
if err = tx.Create(&Product{Code: "D41"}).Error; err != nil{
//事务中处理都用tx,而不是db
tx.Rollback //遇到错误回滚
return
}
tx.Commit() //提交事务
- GORM 提供了Transaction 方法用于自动提交事务,避免用户漏写Commit、Rollback
if err = db.Transaction(func(tx *grom.DB) error {
if err = tx.Create(&Product{Code: "D41"}).Error; err != nil{
return err
}
return nil
}); err != nil {
return
}
拓展
- 性能提高
dsn := "root:ann@tcp(127.0.0.1:3306)/dbgorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: ture, //关闭默认事务
PrepareStmt: true //缓存预编译语句
})
if err != nil {
panic("failed to connect database")
}
- 对于写操作(创建、更新、删除),为了确保数据的完整性,GORM会将他们封装在事务内运行,但是这也会降低性能——使用
SkipDefaultTransaction关闭默认事务 - 提高后续调用的速度——使用
PrepareStmt缓存预编译语句 - 生态(常用扩展如下) | GORM 代码生成工具 | github.com/go-gorm/gen | | --- | --- | | GORM 分片库方案 | github.com/go-gorm/sha… | | GORM 手动索引 | github.com/go-gorm/hin… | | GORM 乐观锁 | github.com/go-gorm/opt… | | GORM 读写分离 | github.com/go-gorm/dbr… | | GORM OpenTelemetry 扩展 | github.com/go-gorm/ope… |