Go的ORM也太拉跨了吧,赶紧给他封装一下

简介: 去年慢慢开始接触了Go语言,也在公司写了几个Go的生产项目。我是从Java转过来的。(其实也不算转,公司用啥,我用啥)在这个过程中,老是想用Java的思维写Go,在开始的一两个月,那是边写边吐槽。

背景
去年慢慢开始接触了Go语言,也在公司写了几个Go的生产项目。我是从Java转过来的。(其实也不算转,公司用啥,我用啥)在这个过程中,老是想用Java的思维写Go,在开始的一两个月,那是边写边吐槽。
丑陋的错误处理,没有流式处理,还竟然没有泛型,框架生态链不成熟,没有一家独大的类似Spring的框架。(其实现在写了快一年的Go,Go还是挺香的,哈哈)
今天,我来聊一下,我在我在写Go过程中用的最多orm框架gorm。
Java的orm
写过Java的基本都知道Mybatis,Mybatis-plus。
在Mybatis-plus中操作单表非常方便,通过QueryWrapper,对于单表的操作非常的丝滑,没有任何的思维负担。
类似下面这样:

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
    userMapper.selectList(queryWrapper);

复制代码
Go的orm
这里的条件查询都需要开发手动来拼接字符串,如果项目比较大的话,就会看到漫天飞的SQL字段,维护起来非常麻烦。
var users []*User
sqlResult := db.Where("username = ? and age = ?", "zhangsan", 18).Find(&users)
复制代码
解决方式
写了一段时间的Go之后,实在不想每次都写这些字符串拼接了,于是我给gorm封装了一个gorm-plus。
这里我使用到了go 1.18的泛型。泛型出了这么久,也该使用上了。
其实就是把Mybatis-plus的那套语法借鉴了一下。(好吧,就是抄他的)
Mybatis-plus对于单表操作提供了非常多的CRUD操作。

我给gorm-plus 也提供了类似的操作

下面是具体用法
下载:
go get github.com/acmestack/gorm-plus
复制代码
初始化sql
DROP TABLE IF EXISTS users;
CREATE TABLE users (

                      `id` int(0) NOT NULL AUTO_INCREMENT,
                      `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                      `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                      `age` int(0) NULL DEFAULT NULL,
                      `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                      `score` int(0) NULL DEFAULT NULL,
                      `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                      `dept` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
                      `created_at` datetime(0) NULL DEFAULT NULL,
                      `updated_at` datetime(0) NULL DEFAULT NULL,
                      PRIMARY KEY (`id`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;
复制代码
连接数据库
var GormDb *gorm.DB

func init() {
dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
var err error
GormDb, err = gorm.Open(mysql.Open(dsn), &gorm.Config{

Logger: logger.Default.LogMode(logger.Info),

})
if err != nil {

log.Fatalln(err)

}
gplus.Init(GormDb)
}
复制代码
插入语句
user := &User{Username: "zhangsan", Password: "123456", Age: 18, Score: 100, Dept: "A部门"}
result := gplus.Insert(user)
fmt.Println(result.RowsAffected)
复制代码
查询语句
根据id查询:
注意这里需要传入泛型User
user, resultDb := gplus.SelectByIdUser
fmt.Println(user, resultDb.RowsAffected)
复制代码
根据ids查询:
var ids = []int{1,2}
users, resultDb := gplus.SelectByIdsUser
复制代码
条件查询:
q := gplus.NewQuery[User]()
q.Eq("username", "zhangsan").Eq("age",18)
users, resultDb := gplus.SelectList(q)
fmt.Println(users,resultDb.RowsAffected)
复制代码
对比一下Mybatis-plus写法基本一致了。

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
    userMapper.selectList(queryWrapper);

复制代码
更多操作请查看:
github.com/acmestack/g…
gplus工具
其实上面的写法还是需要写数据库的字段名,如果数据库的字段名很多,我们很容易写错,导致不必要的bug产生。
一旦名称长,非常容易误写,而且如果有字段名称修改的话,还需要全局搜索一个个地修改,比较麻烦。
Go没有提供类似Java的lambad表达式或者C#中 nameof 方式直接获取某个对象的字段名称的操作,但是我们可以通过生成代码的方式生成字段名。
所有就有了gplus,它作用就是自动识别结构体,把结构体的字段名生成出来。
下载使用:
go install github.com/acmestack/gorm-plus/cmd/gplus@latest
复制代码
通过 gplus gen paths=路径,gplus 会自动识别带有// +gplus:column=true注释的结构体,给这个结构体生成字段。
gplus 会在输入的路径下面生成 zz_gen.column.go文件。
例如:
在example目录下创建了了一个users.go 目录,执行 gplus gen paths=./eample
users.go
// +gplus:column=true

type User struct {
ID int64
Username string gorm:"column:username"
Password string
Address string
Age int
Phone string
Score int
Dept string
CreatedAt time.Time
UpdatedAt time.Time
}
复制代码
zz_gen.column.go (自动生成的)
var UserColumn = struct {
ID string
Username string
Password string
Address string
Age string
Phone string
Score string
Dept string
CreatedAt string
UpdatedAt string
}{
ID: "id",
Username: "username",
Password: "password",
Address: "address",
Age: "age",
Phone: "phone",
Score: "score",
Dept: "dept",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
复制代码
其实你自己也可以手写这个文件,只不过通过工具生成更加方便而已。
有了这个文件,我们的查询就变成这样:
q := gplus.NewQuery[User]()
q.Eq(UserColumn.Username, "zhangsan").Eq(UserColumn.Age,18)
users, resultDb := gplus.SelectList(q)
fmt.Println(users,resultDb.RowsAffected)
复制代码
这样维护起来就非常方便了。

相关文章
|
8月前
|
Go 开发者
掌握Go语言:Go语言结构体,精准封装数据,高效管理实体对象(22)
掌握Go语言:Go语言结构体,精准封装数据,高效管理实体对象(22)
|
SQL 关系型数据库 Go
Go语言微服务框架 - 12.ORM层的自动抽象与自定义方法的扩展
随着接口参数校验功能的完善,我们能快速定位到接口层面的参数问题;而应用服务的分层代码,也可以通过log的trace-id发现常见的业务逻辑问题。 但在最底层与数据库的操作,也就是对GORM的使用,经常会因为我们不了解ORM的一些细节,导致对数据的CRUD失败,或者没有达到预期效果。这时,我们希望能在ORM这一层也有一个通用的解决方案,来加速问题的排查。
94 0
|
关系型数据库 MySQL Go
Go语言微服务框架 - 8.Gormer迭代-定制专属的ORM代码生成工具
我们对比一下GORM库提供的`gorm.Model`,它在新增、修改时,会自动修改对应的时间,这个可以帮我们减少很多重复性的代码编写。这里,我就针对现有的gormer工具做一个示例性的迭代。
107 0
|
安全 Go
Go语言封装艺术:代码安全与结构清晰
Go语言封装艺术:代码安全与结构清晰
93 0
|
2月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
172 4
|
8月前
|
Go API 数据库
【Go 语言专栏】Go 语言中的 ORM 框架使用与比较
【4月更文挑战第30天】本文对比分析了Go语言中的常见ORM框架:GORM、XORM和BeeORM。GORM功能强大,支持复杂查询和关联关系处理,但可能影响性能;XORM以其简单易用和高性能受到青睐,但文档不全;BeeORM简洁高效,适合基础应用场景。选择ORM应考虑功能、性能、易用性和社区支持,根据项目需求进行评估和选择,以提升开发效率和应用性能。
522 0
|
7月前
|
存储 中间件 Go
在go语言服务中封装路由和示例
【6月更文挑战第23天】本文介绍golang后端按协议处理、中间件(一次性与每次请求执行)划分、以及服务架构Controller、Logic/Service、DAO/Repository和Routers划分。代码仓库在GitHub上提供。使用框架简化了交互和处理。后续章节深入探讨服务构建。
179 5
在go语言服务中封装路由和示例
|
5月前
|
编译器 Go
Go语言中的闭包:封装数据与功能的强大工具
Go语言中的闭包:封装数据与功能的强大工具
|
5月前
|
Ubuntu Go Docker
[go]封装go的docker镜像
[go]封装go的docker镜像
|
SQL JavaScript 关系型数据库
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用