Go ORM的封装解决方式详解

 更新时间:2023年01月13日 09:46:38   作者:Afu  
这篇文章主要为大家介绍了Go ORM的封装解决方式详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

背景

去年慢慢开始接触了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.SelectById[User](1)
  fmt.Println(user, resultDb.RowsAffected)

根据ids查询:

  var ids = []int{1,2}
  users, resultDb := gplus.SelectByIds[User](ids)
  fmt.Println(users, resultDb.RowsAffected)

条件查询:

  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)

这样维护起来就非常方便了。

最后

更多的用法请查看github地址:https://github.com/acmestack/gorm-plus

以上就是Go ORM的封装解决方式详解的详细内容,更多关于Go ORM封装的资料请关注脚本之家其它相关文章!

相关文章

  • go使用net/url包来解析URL提取主机部分

    go使用net/url包来解析URL提取主机部分

    这篇文章主要为大家介绍了go使用net/url包来解析URL提取主机部分实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 使用Golang获取音视频时长信息的示例代码

    使用Golang获取音视频时长信息的示例代码

    这篇文章主要介绍了如何使用Golang获取音视频时长信息,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-03-03
  • golang实现openssl自签名双向认证的详细步骤

    golang实现openssl自签名双向认证的详细步骤

    这篇文章主要介绍了golang实现openssl自签名双向认证的详细步骤,本文分步骤给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-03-03
  • golang struct 实现 interface的方法

    golang struct 实现 interface的方法

    这篇文章主要介绍了golang struct 实现 interface的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Go语言Grpc Stream的实现

    Go语言Grpc Stream的实现

    本文主要介绍了Go语言Grpc Stream的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • GoLang BoltDB数据库详解

    GoLang BoltDB数据库详解

    这篇文章主要介绍了GoLang BoltDB数据库,boltdb是使用Go语言编写的开源的键值对数据库,boltdb存储数据时 key和value都要求是字节数据,此处需要使用到 序列化和反序列化
    2023-02-02
  • golang框架中跨服务的最佳通信协议和工具

    golang框架中跨服务的最佳通信协议和工具

    在 go 框架中实现跨服务通信的最佳实践包括使用 grpc(适用于低延迟高吞吐量)、http 客户端(适用于 restful api)和消息队列(适用于异步解耦通信),在选择通信方式时,应考虑服务交互模式、性能要求和部署环境等因素
    2024-06-06
  • 使用Golang实现Sm2加解密的代码详解

    使用Golang实现Sm2加解密的代码详解

    本文主要介绍了Go语言实现Sm2加解密的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • go语言中的协程详解

    go语言中的协程详解

    本文详细讲解了go语言中的协程,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Go中使用加密算法的方法

    Go中使用加密算法的方法

    本文通过实例代码给大家介绍go中使用加密算法的方法,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-08-08

最新评论