• go-zero&go web集成gorm实战


    前言

    上一篇:go-zero&go web集成redis实战

    从零开始基于go-zero搭建go web项目实战-04集成gorm实战
    源码仓库地址 源码 https://gitee.com/li_zheng/treasure-box

    golang gorm

    官网地址:https://gorm.io/zh_CN/docs/index.html

    GORM介绍

    Gorm是Go语言目前比较热门的数据库ORM库,API简单明了,上手容易,使用简单,主要把struct类型和数据库表记录进行映射,操作数据库的时候不需要直接手写SQL,面向结构体,同时也支持手动编写sql进行调优。

    特性

    • 全功能 ORM
    • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
    • Create,Save,Update,Delete,Find 中钩子方法
    • 支持 Preload、Joins 的预加载
    • 事务,嵌套事务,Save Point,Rollback To Saved Point
    • Context、预编译模式、DryRun 模式
    • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
    • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
    • 复合主键,索引,约束
    • Auto Migration
    • 自定义 Logger
    • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
    • 每个特性都经过了测试的重重考验
    • 开发者友好

    GORM 官方支持的数据库类型有:MySQL, PostgreSQL, SQLite, SQL Server 和 TiDB

    安装

    这里使用MySQL数据库进行测试
    安装依赖包

    // 安装MySQL依赖
    go get gorm.io/driver/mysql@v1.3.5
    // 安装Gorm依赖
    go get gorm.io/gorm@v1.25.4
    
    • 1
    • 2
    • 3
    • 4

    简单入门

    创建mysql数据库连接

    import (
      "gorm.io/driver/mysql"
      "gorm.io/gorm"
    )
    
    func main() {
      //连接本地数据库bd01,用户名:root,密码:123456
      dsn := "root:123456@tcp(127.0.0.1:3306)/db01?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai"
      db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • mysql.Open(dsn) 根据提供的连接信息打一个mysql连接器
    • gorm.Open() 在给定 dialector 的基础上开启一个 db session
    • gorm.Config{} 可选配置

    声明一个模型struct,对应数据的一张表,User继承了gorm.Model,拥有gorm.Model的字段信息。

    type User struct {
    	gorm.Model
    	Name    string
    	Sex     int8
    }
    // 指定表名 t_user
    func (User) TableName() string {
    	return "t_user"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    // gorm.Model 的定义,提供默认的字段和类型,GORM 约定使用 CreatedAt、UpdatedAt 追踪创建/更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充 当前时间
    type Model struct {
    ID uint gorm:"primaryKey"
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt gorm.DeletedAt gorm:"index"
    }

    操作数据库,这里给出几个例子,更多操作方式见官网

      // 迁移 schema
      db.AutoMigrate(&User{})
    
      // Create
      db.Create(&User{Name: "张三", Sex: 1})
    
      // Read
      var user User
      db.First(&user, 1) // 根据整型主键查找
      db.First(&user, "name = ?", "张三") // 查找 code 字段值为 D42 的记录
    
      // Update
      db.Model(&user).Update("Name", "李四")
      // Update - 更新多个字段
      db.Model(&user).Updates(User{Name: "王五", Sex: 2}) // 仅更新非零值字段
      db.Model(&user).Updates(map[string]interface{}{"Name": '王五', "Sex": 2})
    
      // Delete - 删除 product
      db.Delete(&user, 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Web集成

    新增配置struct

    在项目原有基础上新增一个数据配置结构体,添加到全局配置 Config 中

    type DbConf struct {
    	Host                     string
    	Port                     int
    	Username                 string
    	Password                 string
    	Db                       string
    	ParamStr                 string `json:",optional"`
    	MaxOpenConns             int    `json:",default=10"`
    	MaxIdleConns             int    `json:",default=5"`
    	ConnMaxIdleTime          int    `json:",default=60"`
    	ConnMaxLifetime          int    `json:",default=60"`
    	SlowThresholdMillisecond int64  `json:",default=1000"`
    }
    
    type Config struct {
    	rest.RestConf
    	Redis redis.RedisConf `json:",optional"`
    	Auth  struct {
    		AccessSecret string
    		AccessExpire int64
    	}
    	Db DbConf `json:",optional"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    yaml中配置数据库

    Db:
      Host: localhost
      Port: 3306
      Username: root
      # 这里密码如果是纯数字需要加引号
      Password: "123456"
      # 数据库名
      Db: test01
      #连接参数字符串拼接形式
      ParamStr: charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai
      #设置打开数据库连接的最大数量
      MaxOpenConns: 10
      #设置空闲连接池中连接的最大数量
      MaxIdleConns: 5
      #连接最大空闲时间 单位秒
      ConnMaxIdleTime: 60
      #设置连接可复用的最大时间 单位秒
      ConnMaxLifetime: 60
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    项目启动加载配置

    这里使用的是go-zero的conf.MustLoad(configFile, &c)方法加载yaml配置,其他方式可自行根据情况进行配置读取,例如使用 gopkg.in/yaml.v2 进行读取。

    conf.MustLoad(configFile, &c)
    
    • 1

    在这里插入图片描述
    gopkg.in/yaml.v2 读取例子

    
    func LoadAppConf(filePath string, out interface{}) error {
    	file, err := ioutil.ReadFile(filePath)
    	if err != nil {
    		return err
    	}
    	err = yaml.Unmarshal(file, out)
    	if err != nil {
    		return err
    	}
    	if conf.Logging.PrintConf {
    		fmt.Println("------------------------------------------", filePath, " Start------------------------------------------>")
    		fmt.Println(string(file))
    		fmt.Println()
    	}
    
    	return nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    初始化数据库连接

    在项目上下文中初始化数据库连接信息,internal/svc/ctx.go 中的 initDb 方法会在服务启动时候调用,进行数据库的初始化,具体代码如下,调用细节可以参考:https://gitee.com/li_zheng/treasure-box 下对应的文件代码

    func initDb() {
    	dbConf := sCtx.Config.Db
    	if len(dbConf.Host) == 0 {
    		return
    	}
    	logx.Infof("Initializing db ...")
    	//if len(dbConf.ParamStr) == 0 {
    	//	dbConf.ParamStr = getParamStr(dbConf.ConnParams)
    	//}
    	dbUrl := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s",
    		dbConf.Username,
    		dbConf.Password,
    		dbConf.Host,
    		dbConf.Port,
    		dbConf.Db,
    		dbConf.ParamStr)
    	logx.Infof("DSN: %s", dbUrl)
    	dialector := mysql.New(mysql.Config{
    		DSN:                       dbUrl, // data source name
    		DefaultStringSize:         256,   // string 类型字段的默认长度
    		DisableDatetimePrecision:  true,  // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
    		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
    		DontSupportRenameColumn:   true,  // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
    		SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
    	})
    
    	newLogger := logger.New(
    		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
    		logger.Config{
    			SlowThreshold:             time.Duration(dbConf.SlowThresholdMillisecond) * time.Millisecond, // 慢 SQL 阈值
    			LogLevel:                  logger.Info,                                                       // 日志级别
    			IgnoreRecordNotFoundError: true,                                                              // 忽略ErrRecordNotFound(记录未找到)错误
    			Colorful:                  true,                                                              // 禁用彩色打印
    		},
    	)
    
    	option := &gorm.Config{
    		//禁用默认全局事务
    		SkipDefaultTransaction: true,
    		//开启预编译sql
    		PrepareStmt: true,
    		Logger:      newLogger,
    	}
    	db, err := gorm.Open(dialector, option)
    	if err != nil {
    		logx.Must(err)
    	}
    	sqlDb, err := db.DB()
    	if err != nil {
    		logx.Must(err)
    	}
    	sqlDb.SetMaxOpenConns(dbConf.MaxOpenConns)
    	sqlDb.SetMaxIdleConns(dbConf.MaxIdleConns)
    	sqlDb.SetConnMaxIdleTime(time.Second * time.Duration(dbConf.ConnMaxIdleTime))
    	sqlDb.SetConnMaxLifetime(time.Second * time.Duration(dbConf.ConnMaxLifetime))
    	sCtx.Db = db
    	logx.Infof("%+v", sqlDb.Stats())
    	logx.Infof("DB Initialized.")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    项目中使用

    在这里插入图片描述

  • 相关阅读:
    Leetcode290. 单词规律
    【树莓派 Pico 基于Arduino IDE编程开发】
    【SpringBoot】启动过程之——SpringApplication初始化及运行
    2022/7/18-7/19
    Redis集群方式
    TensorFlow 的基本概念和使用场景
    从查询语句执行流程看MySQL架构
    软降工程概述----软件过程
    性能分析方法-《性能之巅》笔记
    如何下载PDF版本的专利
  • 原文地址:https://blog.csdn.net/small_to_large/article/details/132829375