这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
GORM
gorm 是字节团队研发的一款面向 golang 的 orm 框架,详见:gorm.io/zh_CN/
DSN
DSN是数据源名称Data Source Name,是应用程序用来请求与ODBC数据源连接的名称。连接到ODBC时,它会存储连接详细信息,例如数据库名称、目录、数据库驱动程序、UserID、password等。
约定
在项目开发中,我们常常秉持着约定大于配置的设计理念,在 gorm 中也有类似的设计,具体表现为:
- 使用名为 ID 的字段作为主键 /
gorm:"primaryKey" - 默认使用结构体名的 蛇形命名 作为表名 / 实现 Tabler 接口更改表名
- ...
model
在 gorm 中,使用结构体进行数据模型的绑定:
// Product gorm model
type Product struct {
ID uint `gorm:"primaryKey"`
Code string `gorm:"column: code;"`
Price uint `gorm:"column: user_id"`
Age int32 `gorm:"default:18"` // default
DeletedAt gorm.DeletedAt // gorm 提供软删除实现
}
// TableName 约定,定义表名
func (Product) TableName() string {
return "product"
}
优化
gorm 默认为每个 sql 操作都开启了事务,可以关闭这一配置来提升执行的性能。同时,gorm 也提供了缓存预编译语句的选项,结合使用场景可以适当打开此配置以复用语句,提高性能。
var config *gorm.Config = &gorm.Config{
SkipDefaultTransaction: true, // 关闭默认 CRUD 事务
PrepareStmt: true, // 缓存预编译语句
}
基础操作
因文档介绍详细,在此仅列出部分常用操作,具体内容可自行查看文档。
- connect
db, _ := gorm.Open(mysql.Open("dsn"))
db.Clauses(clause.OnConflict{DoNothing: true}) // Upsert
- create
tx := db.Create(&Product{Code: "6", Price: 6})
if tx.Error != nil {
fmt.Println(tx.Error)
}
- read
var product Product
// 当使用结构体作为条件查询时,gorm 只查询非零字段(非0,false,""等)不会用于构建查询条件(Map除外)
var products = make([]*Product, 0)
// first 默认按主键升序排序
// 使用 first 时,若查询不到数据会返回 ErrRecordNotFound
// SELECT * FROM table ORDER BY id LIMIT 1
db.First(&product, 1) // 默认整型主键
db.First(&product, "code = ?", "6")
// 使用 find 查询不到数据时不报错
// SELECT * FROM table WHERE name LIKE ''
db.Where("name LIKE ?", "%n%").Find(&products)
// SELECT * FROM table WHERE name = '' AND age >= x
db.Where("code = ? AND age >= ?", "a", 18).Find(&products)
- update
// 使用 Model || Table 设置表名
db.Model(&product).Where("age > ?", 18).Update("Price", 200)
// 使用 struct 更新属性时,只会更新非零值字段(用Map或Select指定字段可以更新)
db.Model(&Product{Id: 1}).Updates(Product{Price: 666})
// 更新选定字段:UPDATE table SET name=x WHERE id=x
db.Model(&Product{Id: 1}).Select("name").Updates(map[string]interface{}{
"name": "hello", "age": 18,
})
- delete
// 拥有软删除能力的 Model 调用 Delete 时,记录不会被真正删除,gorm会将 DeletedAt 置为当前时间,并不再能通过正常的查询方式找到
// 使用 Unscoped 可以查询到被软删除的数据
db.Delete(&product, 1) // 默认整型主键
- transaction
// db#Begin 固化事务连接,返回已开启事务的单独连接对象(从池中摘除
tx = db.Begin()
if err := tx.Create(&Product{Code: "aaa"}).Error; err != nil {
tx.Rollback()
return
}
tx.Commit()
// gorm 提供了 Transaction 方法用于自动提交事务,避免漏写 Commit Rollback
if err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&Product{Code: "aaa"}).Error; err != nil {
return err // auto rollback
}1
return nil // auto commit
}); err != nil {
return
}