Gorm—Go语言数据库框架 | 青训营

153 阅读5分钟

一.Gorm简介

1.什么是Gorm?

Gorm是一个Go语言的数据库框架,它支持对MySQL、PostgreSQL、SQLite和SQL Server等数据库的操作。Gorm提供了一种简洁、灵活且强大的方式来操作数据库,包括创建表、查询数据、更新数据和删除数据等。

2.为什么选择Gorm?

  • 全功能 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…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

3.如何使用Gorm?

安装Gorm需要先安装相应的数据库驱动。例如,要安装MySQL驱动,可以使用命令go get -u gorm.io/gormgo get -u gorm.io/driver/mysql。安装完成后,可以使用Gorm的Open方法连接数据库,例如db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})。其中,dsn是数据库的连接字符串,包含了数据库的地址、用户名、密码等信息。

需要下载mysql驱动:

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

简单连接:

username := "root"  //账号
password := "root"  //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306        //数据库端口
Dbname := "gorm"   //数据库名
timeout := "10s"    //连接超时,10秒

// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
  panic("连接数据库失败, error=" + err.Error())
}
// 连接成功
fmt.Println(db)

高级配置

跳过默认事务: 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,可以在初始化时禁用它,这样可以获得60%的性能提升

db, err := gorm.Open(mysql.Open("gorm.db"), &gorm.Config{
  SkipDefaultTransaction: true,
})

命名策略

gorm采用的命名策略是,表名是蛇形复数,字段名是蛇形单数, 例如:

type Student struct {
  Name      string
  Age       int
  MyStudent string
}

gorm会为我们这样生成表结构:

CREATE TABLE `students` (`name` longtext,`age` bigint,`my_student` longtext)

我们也可以修改这些策略:

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  NamingStrategy: schema.NamingStrategy{
    TablePrefix:   "f_",  // 表名前缀
    SingularTable: false, // 单数表名
    NoLowerCase:   false, // 关闭小写转换
  },
})

二.模型定义

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

定义一张表:

type Student struct {
  ID    uint // 默认使用ID作为主键
  Name  string
  Email *string // 使用指针是为了存空值
}

自动生成表结构:

// 可以放多个
DB.AutoMigrate(&Student{})

AutoMigrate的逻辑是只新增,不删除,不修改(大小会修改)

例如将Name修改为Name1,进行迁移,会多出一个name1的字段

生成的表结构如下:

CREATE TABLE `f_students` (`id` bigint unsigned AUTO_INCREMENT,`name` longtext,`email` longtext,PRIMARY KEY (`id`))

修改大小:

我们可以使用gorm的标签进行修改

有两种方式:

Name  string  `gorm:"type:varchar(12)"`
Name  string  `gorm:"size:2"`

字段标签:

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_"`
}

// 建表语句
CREATE TABLE `students` (
    `name` varchar(12) NOT NULL COMMENT '用户名',
    `uuid` varchar(191) UNIQUE COMMENT '主键',
    `s_email` varchar(32),
    `s_y_addr` varchar(16),
    `s_gender` boolean DEFAULT true,
    PRIMARY KEY (`uuid`)
)

三.查询操作

先使用gorm对单张表进行增删改查

表结构

type Student struct {
  ID     uint   `gorm:"size:3"`
  Name   string `gorm:"size:8"`
  Age    int    `gorm:"size:3"`
  Gender bool
  Email  *string `gorm:"size:32"`
}

添加记录

email := "xxx@qq.com"
// 创建记录
student := Student{
  Name:   "wcy",
  Age:    23,
  Gender: True,
  Email:  &email,
}
DB.Create(&student)

两点需要注意:

  1. 指针类型是为了更好的存null类型,但是传值的时候,也记得传指针
  2. Create接收的是一个指针,而不是值

由于我们传递的是一个指针,调用完Create之后,student这个对象上面就有该记录的信息了,如创建的id

DB.Create(&student)
fmt.Printf("%#v\n", student)  
// main.Student{ID:0x2, Name:"zhangsan", Age:23, Gender:false, Email:(*string)(0x11d40980)}

批量插入:

Create方法还可以用于插入多条记录

var studentList []Student
for i := 0; i < 100; i++ {
  studentList = append(studentList, Student{
    Name:   fmt.Sprintf("机器人%d号", i+1),
    Age:    100,
    Gender: True,
    Email:  &email,
  })
}
DB.Create(&studentList)

根据主键查询:

var student Student
DB.Take(&student, 2)
fmt.Println(student)

student = Student{} // 重新赋值
DB.Take(&student, "4")
fmt.Println(student)

Take的第二个参数,默认会根据主键查询,可以是字符串,可以是数字

根据其他条件查询:

var student Student
DB.Take(&student, "name = ?", "机器人27号")
fmt.Println(student)

使用?作为占位符,将查询的内容放入?

SELECT * FROM `students` WHERE name = '机器人27号' LIMIT 1

这样可以有效的防止sql注入

他的原理就是将参数全部转义,如

DB.Take(&student, "name = ?", "机器人27号' or 1=1;#")

SELECT * FROM `students` WHERE name = '机器人27号' or 1=1;#' LIMIT 1

此外,Gorm还提供了一些常用的查询方法,例如Where、Find、First、Select、Order等,可以方便地进行数据的查询和筛选。Gorm还支持链式查询,可以通过链式调用方法来构建复杂的查询条件。

总之,Gorm是一个功能强大、易于使用和灵活的数据库框架,适用于开发各种类型的Go语言应用程序。