go基于go-zero+gorm+gplus实现优雅操作数据库
go-zero 是有圈内大佬万俊峰开发的,七牛云技术副总裁。go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验(千万日活)。框架概述 | go-zero Documentation。
目录
在日常工作中主要用的是go-zero框架,虽然go-zero框架提供了访问数据库的sqlc和sqlx包,提供了最基本的增删改查方法,但是没有mybatis-plus那种操作单表的方法,所以要不停写sql,例如:查询分页,逻辑删除,修改单个信息,批量删除.....等等,十分繁琐,还有大量重复代码,十分不利于维护,虽然后面用到了go-zero结合gorm框架,但是还是会有各种条件查询都需要开发手动来拼接字符串,如果项目比较大的话,就会看到漫天飞的SQL字段,维护起来非常麻烦。所以就想基于go的框架实现mybatis-plus框架那样的功能。
1.使用框架介绍
1.1go-zero框架:
go-zero 是有圈内大佬万俊峰开发的,七牛云技术副总裁。go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验(千万日活)。
官方文档:框架概述 | go-zero Documentation
1.2.gorm框架:
上一篇文章已经详细介绍过了,如果不了解可以看看这个
1.3.glus框架
Gorm-Plus是Gorm的增强工具,它在保持Gorm原有特性的基础上,为开发者提供了开箱即用的增强功能。通过简化开发流程、提高效率,它为开发者带来了无与伦比的开发体验。如果您渴望尝试一款让开发变得轻松而高效的工具,Gorm-Plus将是您不可错过的选择。
其实就是把Mybatis-plus的那套语法借鉴了一下。(好吧,就是抄他的)
Mybatis-plus对于单表操作提供了非常多的CRUD操作
用go1.18出的泛型也可以实现这些方法,本来我还准备自己琢磨写一套的,突然有一天在github上面看见有人已经写了,那我这里就直接拿来用了(好吧,就是懒)。
总结来说就是一句话:
他山之石,可以攻玉
2.使用
2.1go-zero结合gorm
首先创建项目
注意,需要安装go-zero框架的工具 goctl和go的开发环境
在idea中创建go项目,创建godemo文件夹,然后创建godemo.api文件
执行命令
goctl api go -api mingcheng.api -dir .
生成的项目结构如下
导入所需要的依赖
go get github.com/acmestack/gorm-plus
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
增加配置文件
需要注意的是 config包定义的变量要和配置文件一一对应
然后在svc下的servicecontext.go中创建数据库连接,相当于注册数据库连接对象。
然后在logic层编写业务代码
例如我们现在写一个根据名称查询数据的例子
我们可以看见数据已经被查出来了,但是问题就是:
但是还是会有各种条件查询都需要开发手动来拼接字符串,如果项目比较大的话,就会看到漫天飞的SQL字段,维护起来非常麻烦
想要实现的是不用手动拼接条件。直接用泛型就好啦
2.2使用gplus框架
gplus是基于gorm框架做的一层封装,上手非常简单
2.2.1创建
普通创建
category := model.Category{Name: req.Name, ParentId: req.ParentId, Level: req.Level, CategoryType: req.CategoryType}
//普通添加方法
result := gplus.Insert(&category)
fmt.Println(category.Id)
fmt.Println(result.Error)
fmt.Println(result.RowsAffected)
指定字段创建
//指定字段创建值
result = gplus.Insert(&category, gplus.Select(model.CategoryColumn.Name, model.CategoryColumn.CategoryType))
fmt.Println(category.Id) // 打印插入数据的主键
fmt.Println(result.Error) // 打印 error
fmt.Println(result.RowsAffected) // 打印插入记录的条数
批量创建
//批量插入
categoryList := make([]*model.Category, 0)
res := &model.Category{
Name: "大大的",
Level: 10,
}
res1 := &model.Category{
Name: "小小的",
Level: 10,
}
categoryList = append(categoryList, res, res1)
result := gplus.InsertBatchSize(categoryList, 1000)
fmt.Println(result.Error) // 打印 error
fmt.Println(result.RowsAffected) // 打印插入记录的条数
2.2.2查询
2.2.1根据id查询
//对应数据库表
var category model.Category
//1.根据id查询
item, result := gplus.SelectById[model.Category](543)
category = *item
fmt.Println(item, result.RowsAffected)
fmt.Println(category)
2.2..2根据ids查询
//2.根据ids查询
var ids = []int{542, 543}
categoryList, resultDb := gplus.SelectByIds[model.Category](ids)
fmt.Println(resultDb.Error, resultDb.RowsAffected)
for _, item := range categoryList {
category = *item
fmt.Println(category)
}
2.2.3条件查询单个分类
//3.查询单条记录
query, u := gplus.NewQuery[model.Category]()
query.Eq(u.Name, "六楼")
res, resultDb := gplus.SelectOne(query)
fmt.Println(res, resultDb.Error, resultDb.RowsAffected)
如果遇到下面代码飘红的问题,检查编译器版本(泛型是新特性,旧版本的编译器不支持)
2.2..4 条件查询列表
//4.查询列表
query, u := gplus.NewQuery[model.Category]()
query.Gt(u.CategoryType, 1)
list, resultDb := gplus.SelectList(query)
fmt.Println(resultDb.RowsAffected)
for _, item := range list {
fmt.Println(category)
}
fmt.Println(colum.Name)
2.2.5查询总条数
//5.条件查询记录数量
query, u:= gplus.NewQuery[model.Category]()
query.Gt(u.CategoryType, 1)
count, resultDd := gplus.SelectCount(query)
fmt.Println(count)
fmt.Println(resultDd.Error, resultDd.RowsAffected)
2.2.6分页查询数据
//6.分页查询
query, u = gplus.NewQuery[model.Category]()
page := gplus.NewPage[model.Category](1, 10)
query.Gt(u.CategoryType, 1)
categoryList, resultDb := gplus.SelectPage(page, query)
fmt.Println(resultDb.Error, resultDb.RowsAffected)
fmt.Println(categoryList.Total)
for _, item := range categoryList.Records {
fmt.Println(item)
}
println(category.CategoryType)
2.2.7查询数据是否存在
//7.判断数据是否存在
query, u:= gplus.NewQuery[model.Category]()
query.Eq(u.Name, "八楼")
exists, resultDb := gplus.Exists(query)
fmt.Println(exists)
fmt.Println(resultDb.Error)
2.2.8根据泛型返回数据
返回单条记录
//8.根据泛型返回数据
query, u := gplus.NewQuery[model.Category]()
query.Eq(u.Name, "八楼")
categoryVo, resultDb := gplus.SelectGeneric[model.Category, types.Category](query)
fmt.Println(categoryVo)
fmt.Println(resultDb.Error, resultDb.RowsAffected)
fmt.Println(category.Name)
return resp, nil
返回多条记录
query, u := gplus.NewQuery[model.Category]()
query.Gt(u.CategoryType, 1)
categoryListVo, resultDb := gplus.SelectGeneric[model.Category, []*types.Category](query)
for _, item := range categoryListVo {
// 解析字符串时间
// 解析包含时区信息的时间字符串
createTime, err := time.Parse(time.RFC3339, item.CreateTime)
if err != nil {
fmt.Println(err)
continue
}
timeName := timex.Time2String(createTime)
item.CreateTime = timeName
}
分页返回多条数据
query, q := gplus.NewQuery[model.Category]()
page := gplus.NewPage[types.Category](1, 10)
query.Gt(q.CategoryType, 1)
page, resultDb := gplus.SelectPageGeneric[model.Category, types.Category](page, query)
for _, userVo := range page.Records {
resp.List = append(resp.List, userVo)
}
if resultDb.Error != nil {
fmt.Print(resultDb.Error)
fmt.Print(resultDb.RowsAffected)
}
resp.Total = page.Total
2.3更新
2.3.1根据id更新记录
u := User{ID: 1, Username: "张三", Password: "123456"}
resultDb := gplus.UpdateById[User](&u)
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// UPDATE `users` SET `username`='张三',`password`='123456',`updated_at`='2023-06-03 16:54:37.677' WHERE `id` = 1
上面的方式,默认是不更新零值得,如果需要更新零值,可以使用UpdateZeroById
2.3.2 选择字段更新
u := User{ID: 1, Username: "张三", Password: "123456"}
resultDb := gplus.UpdateZeroById[User](&u)
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// UPDATE `users` SET `username`='张三',`password`='123456',`address`='',`age`=0,`phone`='',`score`=0,`dept`='',`created_at`='0000-00-00 00:00:00',`updated_at`='2023--03 16:56:01.117' WHERE `id` = 1
2.3.3 忽略字段更新
u := User{ID: 1, Username: "张三", Age: 20, Password: "123456", Score: 18, Address: "北京", Dept: "开发"}
model := gplus.GetModel[User]()
resultDb := gplus.UpdateById[User](&u, gplus.Select(&model.Username, &model.Password))
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// UPDATE `users` SET `username`='张三',`password`='123456',`updated_at`='2023-06-03 17:02:36.579' WHERE `id` = 1
2.3.4 根据条件更新
q, u := gplus.NewQuery[User]()
q.Eq(&u.ID, 1).Set(&u.Score, 60)
resultDb := gplus.Update(q)
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// UPDATE `users` SET `score`=60,`updated_at`='2023-06-03 16:58:11.93' WHERE id = 1
2.4 删除
2.4.1 根据id删除
resultDb := gplus.DeleteById[User](6)
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// DELETE FROM `users` WHERE `id` = 6
2.4.2 根据多个id删除
resultDb := gplus.DeleteByIds[User]([]int{7, 8, 9})
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// DELETE FROM `users` WHERE `id` IN (7,8,9)
2.4.3 根据条件删除
query, u := gplus.NewQuery[User]()
query.Eq(&u.Username, "afumu")
resultDb := gplus.Delete[User](query)
fmt.Println(resultDb.Error)
fmt.Println(resultDb.RowsAffected)
// DELETE FROM `users` WHERE username = 'afumu'
3.总结
优点:
- 无侵入、增强而非改变:Gorm-Plus以无侵入的方式对 Gorm 进行增强,保持原有特性的同时提供更多功能,让您无需担心兼容性问题。
- 强大的 CRUD 操作和通用查询:Gorm-Plus内置了强大的 CRUD 操作功能,并提供了简便的通用查询功能,无需繁琐的配置即可轻松构建复杂条件查询。
- 支持指针字段形式查询:通过支持指针字段形式查询,Gorm-Plus让编写各类查询条件变得更加便捷,再也不用担心因为字段写错而出现错误。
- 内置泛型查询和灵活的返回类型封装:Gorm-Plus内置了泛型查询功能,让您能够灵活封装返回类型,轻松应对各种查询需求。
- 内置分页插件:Gorm-Plus还提供了内置的分页插件,让分页操作变得简单而高效,让您能够轻松处理大量数据,并实现更好的用户体验。
缺点:
1.无sql,出现问题排除错误有些麻烦。
2.无缓存,每次都直接请求到数据库(可以自己写一套)
3. 封装力度大,对新手不太友好
更多推荐
所有评论(0)