这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
Gorm
Gorm是一个基于go的支持各类数据库操作的框架,支持Mysql、SQLServer、PostgreSQL、SQLite。通过驱动连接数据库,若要连接其他类型数据库,可以复用/开发响应驱动。
通过本篇文章你能了解到Gorm的一些基本操作,更多内容移步官方网站。
模型
记住几个关键点:
- Gorm使用ID字段作为主键
- 结构体的蛇形复数作为表名
- 字段名的蛇形作为列名
如下面的结构的表名是roducts,列有id, price
type Product struct {
ID uint `gorm:"primarykey"`
Price uint `gorm:"column: price, default: 100"`
}
在以上的结构中,我们可以添加各种各样的属于gorm的tag
迁移
gorm中有一个非常便捷的功能是迁移功能,可以将最新的model(数据表)同步给数据库,包括字段类型、大小、主键、自增、外键等等。
在配置完model后,就可以通过一行代码来完成数据表的创建、同步等:
b.AutoMigrate(&Product{})
连接
查看 github.com/go-sql-driv… 了解什么是DSN
db, err := gorm.Open(mysql.Open(dns), &gorm.Config{})
在连接后,通知需要设置一下连接池的配置:
// Initialize sql config
sqlDB, err := db.DB()
utils.CheckPanicErr(err)
sqlDB.SetMaxIdleConns(config.GetInt("max_idle")) // 最大空闲连接池
sqlDB.SetMaxOpenConns(config.GetInt("max_open")) // 最大可用连接池
基本操作
创建
db.Create(&model)
db.Create(&models)
查询
- 使用First查询不到数据会返回错误
- 使用Find查询不到数据不会返回错误,返回空数组
- Where传入结构体会忽略空值零值false,传入Map可避免该问题
db.First(&model, conditions)
db.Where(query, args...).Find(&models)
db.Where(&model).Find(xxx)
db.Where(map).Find(xxx)
更新
db.Model来提前指定表名和更新项
db.Model(&model).Update(column, value);
db.Model(&model).Update(newModel); // 此处不写db.Model,有兜底逻辑
db.Model(&model).Update(map);
删除
- 物理删除
db.Delete(&model, condition)
- 软删除
软删除时,Gorm更新deleteAt为当前时间,并未真正删除,但会查询不到。
type User struct {
ID uint
Deleted gorm.DeletedAt
}
db.Delete(&model)
事务
- Begin, Commit, Rollback函数
- 借Transaction简化操作
// Way 1
tx := db.Begin()
if err := tx.Create(...).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
// Way 2
if err = db.Transction(func(tx *gorm.DB) error {
if err = tx.Create(...).Error; err != nil {
return err
}
return nil
}); err != nil {
return
}
日志
数据库操作日志在有时候必不可少,gorm 官方提供的方案是:
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Silent, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: false, // 禁用彩色打印
},
)
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
Logger: newLogger,
})
那么如果我们想将日志写入文件,就可以修改log.New的入参:
writer, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND, 0666)
// ...
log.New(writer, "/r/n", log.LstdFlags)
性能
性能方面有很多配置,如
- SkipDefaultTransction 关闭默认事务
- PrepareStmt 缓存预编译