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实战 获取代码
wx

关注公众号

©2017-2023 鲁ICP备17023316号-1 Powered by Hugo