今天开始写Golang之 ORM 和 Gorm

467 阅读6分钟

截屏2022-07-15 08.56.03.png

今天继续go的学习,在上一部分我们主要对gin框架进行了讲解,并且介绍了一种和数据库链接的方法,今天我们来讲讲 ORMGorm

什么是ORM?

ORM其实就是(Object Relational Mapping),对象关系映射的意思。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库。

简单的说在go中,就是将数据库和结构体(struct)绑定产生一个关联的过程。

GORM

什么是gorm呢?下面我们请Gorm来做下自我介绍:

官网:gorm.io/zh_CN/

The fantastic ORM library for Golang aims to be developer friendly.

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

Gorm实际也就是个ORM,它的作用是在对开发者友好的前提下对数据库进行操作。

类似于Java里的Mybatis。

快速上手

首先 老规矩 先创建好项目,在项目路径下输入:

下载gorm库

go get -u gorm.io/gorm

创建数据库以及测试表

这一部没啥说的,都懂。

我的数据库为:go_db

测试表为:user

表结构如下:

CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1005 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

创建main并创建表结构

type User struct {
   ID   int64  `gorm:"column:id;primary_key"`
   Name string `gorm:"type:varchar(255);column:name"`
   Age  int    `gorm:"column:age"`
}

ps:字段名必须大写。

你可能发现了,结构体后出现了独特的约定方式,这是gorm的约定。

默认情况下,GORM 会使用 ID 作为表的主键。如果你的主键不是ID则需要指定gorm:"primary_key"

创建和数据库的链接

func main

db, connErr := gorm.Open("driver", "username:password@tcp(127.0.0.1:3306)/db_name?charset=utf8&parseTime=True&loc=Local")

if connErr != nil {
   panic("failed to connect database")
}

defer db.Close() //异步关闭
db.SingularTable(true)

主要第一句需要替换 driver``,usernamepassworddb_name,如果你的数据库端口地址有变那也需要修改。

SingularTable的作用:

在Gorm中,表名是 结构体 名的复数形式,列名是字段名的 蛇形小写。即,如果有一个user表,那么如果你定义的结构体名为:User,gorm会默认表名为users而不是user

db.SingularTable(true) 让grom转义struct名字的时候不用加上s

CRUD

Create 新增一条数据

theUser := User{Name: "TT", Age: 22} //创建一条数据

db.Create(&theUser) //新增数据,新ID会放在theUser中

fmt.Println("new key is:", theUser.ID) //让我们看看成功后的ID

Retrieve 检索

首先 gorm 具备多种查询方式,如:

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;


// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;

// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

它们的使用方式很简单(以frist为例):

var theStudent User //创建实例
db.First(&theStudent) //查询第一条数据,并把数据放到实例
fmt.Println(theStudent) //看看数据

其他几个也大同小异。

条件查询:

var theUser User
db.Where("name = ?", "TT").First(&theUser)
fmt.Println(theUser)

如上例子,就是查询名字为TT的第一条数据的方式,查询基本都需要和实例挂钩。

where查询可以和基本的查询挂钩,如FristLast

查询全部:

userList := make([]*User, 0) //创建User切片
db.Find(&userList) //通过Find查询全部,并放到切片中。
for _, v := range userList { //查看数据
   fmt.Println(*v)
}

此处需要注意查询全部必须放到切片中

更多查询方法:gorm.io/zh_CN/docs/…

Update 更新

基本的方法:

Save

// Save 会更新全部列,即使字段是零值的也会保存
db.Save(&user)

更新单个列

// 条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

// User 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

更新多列

// 根据 `struct` 更新属性,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

// 根据 `map` 更新属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

实例: 更新单列。

var theUser User
db.Where("name = ?", "TT").First(&theUser) //查询名字为TT的
fmt.Println(theUser)

db.Model(&theUser).Update("name", "Tyler") //将TT改名为Tyler
fmt.Println(theUser)

更新多列,通过结构体

var theUser User
db.Where("name = ?", "Tyler").First(&theUser) //查询名为Tyler的数据
fmt.Println(theUser)

theUser.Name = "TT" //改名TT
theUser.Age = 18 //改年纪

db.Model(&theUser).Updates(theUser) //更新操作
fmt.Println(theUser)

Delete 删除

删除的基本方式:

结构体删除:

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

条件删除:

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

主键删除:

//主键删除
db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

例子:

var theUser User
db.Last(&theUser)
fmt.Println(theUser)

db.Delete(&theUser) //删除最后一条

如果你看到这里,恭喜你,已经学会了基本的CRUD了,这里只列举了部分基础技巧,当你有具体需求时可以去官方文档查看:gorm.io/zh_CN/


其它技巧

通过结构体创建数据表

此时我需要有一个新的数据库book,它记录书名ISBNISBN作为主键。

按照传统方式,我们需要先建数据库,但是在gorm中我们并不需要这样,只需要你创建好结构体,调用方法就足够了。

结构体:

type book struct {
   ID   int64  `gorm:"column:id"`
   Name string `gorm:"column:name"`
   ISBN int    `gorm:"column:isbn;primary_key"`
}

你可以看到我的主键是ISBN

如何通过结构体进一步创建数据表呢?

调用DB.AutoMigrate()方法就足够了。

db, connErr := gorm.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/go_db?charset=utf8&parseTime=True&loc=Local")
if connErr != nil {
   panic("failed to connect database")
}
defer db.Close()
db.SingularTable(true)
db.AutoMigrate(&book{})

总结

gorm是一个很强大的工具,这里我只是列举了一些简单的方法,还有很多很强大的功能等待你去发现。


我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿