今天继续go的学习,在上一部分我们主要对gin框架进行了讲解,并且介绍了一种和数据库链接的方法,今天我们来讲讲 ORM 和 Gorm。
什么是ORM?
ORM其实就是(Object Relational Mapping),对象关系映射的意思。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库。
简单的说在go中,就是将数据库和结构体(struct)绑定产生一个关联的过程。
GORM
什么是gorm呢?下面我们请Gorm来做下自我介绍:
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``,username,password,db_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查询可以和基本的查询挂钩,如Frist,Last
查询全部:
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,它记录书名,ISBN,ISBN作为主键。
按照传统方式,我们需要先建数据库,但是在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是一个很强大的工具,这里我只是列举了一些简单的方法,还有很多很强大的功能等待你去发现。
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。