Gin实战6:Gorm操作数据库实现Repo

一、ORM 选择
Golang比较流行的ORM 框架有 Gorm、Xorm、Beego orm 等,这里选择使用Gorm。 Gorm 是一个 Go 语言编写的 ORM 框架, Gorm Gen 是一个 Gorm 的代码生成器,用于生成 Model 对象,从而实现对数据库的操作。
二、生成Model
1、 创建数据库
CREATE DATABASE IF NOT EXISTS `study_gen` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
2、 创建表
CREATE DATABASE IF NOT EXISTS `study_gin` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
DROP TABLE IF EXISTS `study_gin`.`account`;
CREATE TABLE IF NOT EXISTS `study_gin`.`account` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COMMENT '用户名',
`password` VARCHAR(255) NOT NULL COMMENT '密码',
`email` VARCHAR(255) NOT NULL COMMENT '邮箱',
`status` INT NOT NULL COMMENT '状态 1启用 2禁用',
`create_at` INT NOT NULL DEFAULT 0 COMMENT '创建时间',
`update_at` INT NOT NULL DEFAULT 0 COMMENT '更新时间',
`deleted_at` INT NOT NULL DEFAULT 0 COMMENT '删除时间',
PRIMARY KEY (`id`),
UNIQUE INDEX `name` (`name`)
) ENGINE = InnoDB comment '用户表';
3、 生成Model data/gen/gen.go 中实现主要生成model代码主要逻辑:
- 读取数据库配置
- 生成model代码,
- 设置 deleted_at 字段为软删除字段
//go:generate go run ./... --conf=../../../configs
var (
flagconf string
)
func init() {
flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
}
func main() {
flag.Parse()
appConfig := &conf.AppConfig{}
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(flagconf)
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
if err := viper.Unmarshal(&appConfig); err != nil {
panic(err)
}
var wg sync.WaitGroup
var dsn = appConfig.Data.Database.Source
GenModelsFromDb(dsn, "../query")
wg.Wait()
fmt.Println("done !!!")
}
func GenModelsFromDb(dsn, path string) {
g := gen.NewGenerator(gen.Config{
OutPath: path,
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
})
gormdb, err := gorm.Open(mysql.Open(dsn))
if err != nil {
fmt.Println("gorm open error:", err)
return
}
g.UseDB(gormdb)
g.WithOpts(gen.FieldType("deleted_at", "soft_delete.DeletedAt"))
tables := g.GenerateAllTable()
if len(tables) == 0 {
fmt.Println("no tables found")
return
}
g.ApplyBasic(tables...)
// Generate the code
g.Execute()
}
Makefile 增加生成model的命令
.PHONY: model
model:
go generate ./internal/data/...
执行 make model
生成代码
三、data连接数据库
data/data.go 中实现主要逻辑:
- 配置数据库连接,实现获取连接对象方法
type Data struct {
db *gorm.DB
}
func (d *Data) DB(ctx context.Context) *query.Query {
return query.Use(d.db)
}
func NewData(conf *conf.Data) *Data {
return &Data{
db: NewGormDB(conf),
}
}
func NewGormDB(conf *conf.Data) *gorm.DB {
db, err := gorm.Open(mysql.Open(conf.Database.Source))
if err != nil {
panic(err)
}
sqlDB, err := db.DB()
if err != nil {
panic(err)
}
sqlDB.SetMaxIdleConns(100)
sqlDB.SetMaxOpenConns(200)
sqlDB.SetConnMaxLifetime(time.Hour)
return db.Debug()
}
四、实现 Repo
data/account.go 中实现biz 定义的接口,这里我们使用query 进行操作。
type AccountRepo struct {
data *Data
}
func (a *AccountRepo) GetByUsername(ctx context.Context, username string) (*biz.Account, error) {
account := a.data.DB(ctx).Account
user, err := account.Where(account.Name.Eq(username)).First()
if err != nil {
return nil, err
}
return &biz.Account{
Username: user.Name,
Password: user.Password,
UserID: user.ID,
}, nil
}
func NewAccountRepo(data *Data) biz.AccountRepo {
return &AccountRepo{
data: data,
}
}
var _ biz.AccountRepo = (*AccountRepo)(nil)
data 层实现了 Repo 接口,实现了对数据库的操作。 NewData
加入 ProviderSet
后重新生成依赖注入代码,实现对数据库的操作。
总结
- 通过 Gorm Gen 生成 Model 代码,实现了对数据库的操作。同时可以定义表之间的关联关系,使用Preload 更快速查询数据。
- 预告:事务处理由data层移到biz层控制;
- 回复 Gin实战 获取代码
