Go语言之Gorm框架(一) ——初窥Gorm框架

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
日志服务 SLS,月写入数据量 50GB 1个月
简介: Go语言之Gorm框架(一) ——初窥Gorm框架

Gorm和Mysql驱动的安装

打开终端,输入下列命令即可:

go get gorm.io/driver/mysql
go get gorm.io/gorm

Gorm连接数据库

示例

package main
import (
  "fmt"
  "github.com/sirupsen/logrus"
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)
func init() {
  //数据库连接信息
  username := "root"
  password := "123456"
  databasename := "gorm"
  localHost := "localhost"
  port := 3306
  dns := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local",
    username, password, localHost, port, databasename)
  db, err := gorm.Open(mysql.Open(dns))
  if err != nil {
    logrus.Error("数据库连接失败", err)
  }
  fmt.Println("数据库连接成功", db)
}
func main() {
}

数据库连接的细节

  • 跳过默认事务
    为了保证数据一致性,Gorm会在事务中去执行去执行增删查改,如果我们没有这个需求可以选择跳过默认事务:
db, err := gorm.Open(mysql.Open(dns),&gorm.Config{SkipDefaultTransaction: true})
  • 命名策略
    在grom中默认表名是复数,字段是单数,比如下面我们创建一张student表,代码是这样的:
package main
import (
  "fmt"
  "github.com/sirupsen/logrus"
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)
var dB *gorm.DB
type Student struct {
  Name string
  Age  int
  Sex  string
}
func init() {
  //数据库连接信息
  username := "root"
  password := "ba161754"
  databasename := "gorm"
  localHost := "localhost"
  port := 3306
  dns := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local",
    username, password, localHost, port, databasename)
  db, err := gorm.Open(mysql.Open(dns), &gorm.Config{SkipDefaultTransaction: true})
  if err != nil {
    logrus.Error("数据库连接失败", err)
  }
  dB = db
}
func main() {
  err := dB.AutoMigrate(Student{})
  if err != nil {
    logrus.Error("数据库迁移失败", err)
  }
  fmt.Println("创建表成功")
}

创建出来的表是这样的:

当然我们也可以尝试修改这种命名策略:

db, err := gorm.Open(mysql.Open(dns), &gorm.Config{SkipDefaultTransaction: true,
    NamingStrategy: schema.NamingStrategy{   //
      TablePrefix:   "t_",  //表名前缀
      SingularTable: false, //禁用表名复数
      NoLowerCase:   false, //禁用小写
    }})
  • 日志显示
func initLogger() {
  var mysqlLogger logger.Interface
  mysqlLogger = logger.Default.LogMode(logger.Info) //设置日志打印级别
  mysqlLogger = logger.New(
    log.New(os.Stdout, "\r\n", log.LstdFlags), // (日志输出的目标,前缀和日志包含的内容)
    logger.Config{
      SlowThreshold:             time.Second, // 慢 SQL 阈值
      LogLevel:                  logger.Info, // 日志级别
      IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
      Colorful:                  true,        // 使用彩色打印
    },
  )
  dB.Logger = mysqlLogger
}

完整代码,仅供参考:

package main
import (
  "fmt"
  "github.com/sirupsen/logrus"
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
  "gorm.io/gorm/logger"
  "gorm.io/gorm/schema"
  "log"
  "os"
  "time"
)
var dB *gorm.DB
type Student struct {
  Name string
  Age  int
  Sex  string
}
func ConnectDB() {
  //数据库连接信息
  username := "root"
  password := "ba161754"
  databasename := "gorm"
  localHost := "localhost"
  port := 3306
  var err error
  dns := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local",
    username, password, localHost, port, databasename)
  dB, err = gorm.Open(mysql.Open(dns), &gorm.Config{SkipDefaultTransaction: true,
    NamingStrategy: schema.NamingStrategy{ //
      TablePrefix:   "t_",  //表名前缀
      SingularTable: false, //禁用表名复数
      NoLowerCase:   false, //禁用小写
    }})
  if err != nil {
    logrus.Error("数据库连接失败", err)
  }
}
func initLogger() {
  var mysqlLogger logger.Interface
  mysqlLogger = logger.Default.LogMode(logger.Info) //设置日志打印级别
  mysqlLogger = logger.New(
    log.New(os.Stdout, "\r\n", log.LstdFlags), // (日志输出的目标,前缀和日志包含的内容)
    logger.Config{
      SlowThreshold:             time.Second, // 慢 SQL 阈值
      LogLevel:                  logger.Info, // 日志级别
      IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
      Colorful:                  true,        // 使用彩色打印
    },
  )
  dB.Logger = mysqlLogger
}
func init() {
  ConnectDB()
  initLogger()
}
func main() {
  err := dB.AutoMigrate(Student{})
  if err != nil {
    logrus.Error("数据库迁移失败", err)
  }
  fmt.Println("创建表成功")
}

模型定义

模型定义示例

模型是使用普通结构体定义的。 这些结构体可以包含具有基本Go类型、指针或这些类型的别名,甚至是自定义类型(只需要实现 database/sql 包中的Scanner和Valuer接口)我们来看一下Gorm给出的user模型示例:

type User struct {
  ID           uint           // Standard field for the primary key
  Name         string         // 一个常规字符串字段
  Email        *string        // 一个指向字符串的指针, allowing for null values
  Age          uint8          // 一个未签名的8位整数
  Birthday     *time.Time     // A pointer to time.Time, can be null
  MemberNumber sql.NullString // Uses sql.NullString to handle nullable strings
  ActivatedAt  sql.NullTime   // Uses sql.NullTime for nullable time fields
  CreatedAt    time.Time      // 创建时间(由GORM自动管理)
  UpdatedAt    time.Time      // 最后一次更新时间(由GORM自动管理)
}

这里常见的uint这种类型就不做过多介绍了,这里主要是 有两个类型我们这里进行一下介绍:

  • *string(指针类型) :如果我们在这里使用string类型的话,这里我们是可以写空值的,如果我们用string类型是不允许出现空值的
  • sql.NullString sql.NullString 是 Go 语言标准库中的一个数据类型,位于 database/sql 包中。它用于表示数据库中可能为 NULL 的字符串值。它由两个字段组成:String 用于保存字符串值(如果不为 NULL),Valid 是一个布尔标志,指示字符串值是否为 NULL。在与允许字符串列包含 NULL 值的数据库一起工作时,这种类型特别有用。
type NullString struct {
  String string
  Valid  bool // Valid is true if String is not NULL
}

gorm.Model

在开始介绍gorm.Model之前,我们先讲一下几条在gorm的约定:

-主键:GORM 使用一个名为ID 的字段作为每个模型的默认主键。

  • 表名:默认情况下,GORM 将结构体名称转换为 snake_case 并为表名加上复数形式。 例如,一个 User 结构体在数据库中的表名变为 users 。
  • 列名:GORM 自动将结构体字段名称转换为 snake_case 作为数据库中的列名。
  • 时间戳字段:GORM使用字段 CreatedAt 和 UpdatedAt 来自动跟踪记录的创建和更新时间。

而在grom中存在gorm.Model这一预定义的结构体,我们可以将它直接嵌入我们所定义的结构体中,这保证了不同模型之间保持一致性并利用GORM内置的约定,gorm.model的定义如下:

type Model struct {
  ID        uint `gorm:"primarykey"` 
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt DeletedAt `gorm:"index"`
}

它主要包含以下字段:

  • ID :每个记录的唯一标识符(主键)。
  • CreatedAt :在创建记录时自动设置为当前时间。
  • UpdatedAt:每当记录更新时,自动更新为当前时间。
  • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)。

字段标签

gorm中我们一般使用字段标签来表示字段的类型,常见的字段类型主要有以下几种:

  • type:定义字段类型
  • size:字段大小
  • column 自定义别名
  • primaryKey 将列定义为主键
  • unique 将列定义为唯一键
  • default 定义列的默认值
  • not null 不可为空
  • embedded 嵌套字段
  • embeddedPrefix 嵌套字段前缀
  • comment 注释

示例:

type StudentInfo struct {
 Email  *string `gorm:"size:32"` // 使用指针是为了存空值
 Addr   string  `gorm:"column:y_addr;size:16"`
 Gender bool    `gorm:"default:true"`
}
type Student struct {
 Name string      `gorm:"type:varchar(12);not null;comment:用户名"`
 UUID string      `gorm:"primaryKey;unique;comment:主键"`
 Info StudentInfo `gorm:"embedded;embeddedPrefix:s_"`
}
相关文章
|
17小时前
|
编译器 Go 开发者
Go语言语法基础入门
Go语言语法基础入门
4 0
|
19小时前
|
Devops Go 云计算
Go语言发展现状:历史、应用、优势与挑战
Go语言发展现状:历史、应用、优势与挑战
8 2
|
1天前
|
Go
go语言map、实现set
go语言map、实现set
9 0
|
1天前
|
Go
go语言数组与切片
go语言数组与切片
10 0
|
1天前
|
Go
go语言的hello,world
go语言的hello,world
6 1
|
7天前
|
中间件 Go
go语言后端开发学习(三)——基于validator包实现接口校验
go语言后端开发学习(三)——基于validator包实现接口校验
|
7天前
|
存储 Go 开发工具
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
|
7天前
|
JSON 算法 Go
go语言后端开发学习(一)——JWT的介绍以及基于JWT实现登录验证
go语言后端开发学习(一)——JWT的介绍以及基于JWT实现登录验证
|
1月前
|
缓存 负载均衡 网络协议
使用Go语言开发高性能服务的深度解析
【5月更文挑战第21天】本文深入探讨了使用Go语言开发高性能服务的技巧,强调了Go的并发性能、内存管理和网络编程优势。关键点包括:1) 利用goroutine和channel进行并发处理,通过goroutine池优化资源;2) 注意内存管理,减少不必要的分配和释放,使用pprof分析;3) 使用非阻塞I/O和连接池提升网络性能,结合HTTP/2和负载均衡技术;4) 通过性能分析、代码优化、缓存和压缩等手段进一步提升服务性能。掌握这些技术能帮助开发者构建更高效稳定的服务。
|
1月前
|
Kubernetes Cloud Native Go
Golang深入浅出之-Go语言中的云原生开发:Kubernetes与Docker
【5月更文挑战第5天】本文探讨了Go语言在云原生开发中的应用,特别是在Kubernetes和Docker中的使用。Docker利用Go语言的性能和跨平台能力编写Dockerfile和构建镜像。Kubernetes,主要由Go语言编写,提供了方便的客户端库与集群交互。文章列举了Dockerfile编写、Kubernetes资源定义和服务发现的常见问题及解决方案,并给出了Go语言构建Docker镜像和与Kubernetes交互的代码示例。通过掌握这些技巧,开发者能更高效地进行云原生应用开发。
84 1