GO是否需要一个类似于MybatisPlus的全自动ORM框架?

2023年 7月 16日 69.2k 0

背景

去年慢慢开始接触了Go语言,在接触了一些Go的ORM框架之后,感觉用的不是很顺手,之后萌生了写一个Go版本的全自动ORM框架的想法。本来想着从零开始实现的,但是又觉得工作量挺大的,何不站在巨人肩膀上造一个呢。

于是我在Grom的基础上写了一个Gorm-plus,之后在掘金就发一篇简单的介绍。Go的ORM也太拉跨了吧,赶紧给他封装一下

image.png

这也引来了一些社区朋友的探讨

image.png

image.png

image.png

更多评论可以到这个文章查看 Go的ORM也太拉跨了吧,赶紧给他封装一下

我简单总结一下,主要为以下几个观点:

  • 对gorm-plus这种基于gorm做orm封装的看法不一,有人认为太啰嗦,有人认为挺好用的。这主要取决于个人习惯和喜好。
  • 有人建议可以试试其他orm框架,如ent、xorm、goframe的orm等。
  • 有人认为还是直接使用sql语句更简单直接。
  • 有人认为这种代码拼sql的方式不如使用IDE自动生成的sql直观。
  • 也有人认为基于命名约定的gorm方式更符合golang的思想,简单易用。
  • 一些人建议可以试试gorm自带的gen工具自动生成代码。
  • 个别评论表示这种方式反映了以java思维编写golang代码的影响。
  • 也有观点认为相比java的orm框架,golang的orm还不够成熟。
  • 总的来说,社区朋友对这种基于Gorm做二次封装的ORM库看法不一,主要集中在Java和Golang思维差异、各orm框架比较、直接SQL与ORM的选择等方面。但整体而言还是以积极的态度探讨和建议的多。

    疑惑

    为什么Go到目前为止都没有一个全自动的ORM框架呢?

    我搜集了一些回答

  • Go语言的设计哲学本身就追求简洁,反对过度的抽象和封装。全自动ORM框架更加复杂,与Go语言的定位不太配。

  • Go语言标准库自身就提供了database/sql等数据库访问相关功能,大多数项目直接使用标准库就能满足需求。

  • Go语言拥有很高的执行效率,引入全自动ORM的大量反射、缓存等机制,可能会带来显著的性能损失。

    我的看法:
    大规模用户场景下,数据库承载了主要的读写压力,成为性能瓶颈。
    ORM框架的反射和缓存开销相比数据库操作时间其实是很少的。
    Go语言本身执行效率很高,ORM框架的语言层面影响较小

  • 开源的Go项目多由小团队或个人开发,不像Java有大公司或机构推动开发大型框架。

    我的看法:
    Go语言自身定位为简洁高效,对复杂框架需求不高,由小团队就可以满足需求。
    Go生态发展时间不长,很多公司还在观望阶段,没有充分投入。
    Go社区文化更注重简单直接,不追求框架化。
    相对Java等语言,Go应用场景还更侧重后端,框架需求没那么强烈。

  • Go语言目前应用场景以后端服务居多,对 ORM需求没有网页类应用那么强烈。

  • 一些轻量级的ORM框架已基本满足需求,没有出现推动全自动ORM成熟的力量。

  • 结论

    根据上期文章社区朋友的评论和我收集到的一些回答,我觉得全自动ORM框架还是有一定的必要的,所以这次我又更新了一些新的功能,希望对有需要的朋友带来一些帮助。

    快速上手

    现有一张 Users 表,其表结构如下:

    CREATE TABLE `users` (
      `id` bigint NOT NULL AUTO_INCREMENT,
      `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
      `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
      `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
      `age` bigint DEFAULT NULL,
      `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
      `score` bigint DEFAULT NULL,
      `dept` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
      `created_at` datetime(3) DEFAULT NULL,
      `updated_at` datetime(3) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=407 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    
    

    对应的数据如下:

    INSERT INTO `users` (`username`, `password`, `address`, `age`, `phone`, `score`, `dept`, `created_at`, `updated_at`)
    VALUES
      ('张三', 'password1', '地址1', 25, '12345678901', 80, '部门1', NOW(), NOW()),
      ('李四', 'password2', '地址2', 30, '12345678902', 90, '部门2', NOW(), NOW()),
      ('王五', 'password3', '地址3', 35, '12345678903', 70, '部门1', NOW(), NOW()),
      ('赵六', 'password4', '地址4', 28, '12345678904', 85, '部门2', NOW(), NOW()),
      ('钱七', 'password5', '地址5', 32, '12345678905', 75, '部门1', NOW(), NOW());
    
    

    开始使用

    下载Gorm-Plus

    go get github.com/acmestack/gorm-plus
    
    package main
    
    import (
      "github.com/acmestack/gorm-plus/gplus"
      "gorm.io/driver/mysql"
      "gorm.io/gorm"
      "gorm.io/gorm/logger"
      "log"
      "time"
    )
    
    type User struct {
      ID        int64
      Username  string
      Password  string
      Address   string
      Age       int
      Phone     string
      Score     int
      Dept      string
      CreatedAt time.Time
      UpdatedAt time.Time
    }
    
    var gormDb *gorm.DB
    
    func init() {
      dsn := "root:123456@tcp(127.0.0.1:3306)/test?&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.Println(err)
      }
    
      // 初始化gplus
      gplus.Init(gormDb)
    }
    
    func main() {
      users, resultDb := gplus.SelectList[User](nil)
      log.Println("error:", resultDb.Error)
      log.Println("RowsAffected:", resultDb.RowsAffected)
      for _, user := range users {
        log.Println("user:", user)
      }
    }
    
    

    控制台输出:

    2023/06/01 17:48:19 error: 
    2023/06/01 17:48:19 RowsAffected: 5
    2023/06/01 17:48:19 user: &{1 张三 password1 地址1 25 12345678901 80 部门1 2023-06-01 17:48:11 +0800 CST 2023-06-01 17:48:11 +0800 CST}
    2023/06/01 17:48:19 user: &{2 李四 password2 地址2 30 12345678902 90 部门2 2023-06-01 17:48:11 +0800 CST 2023-06-01 17:48:11 +0800 CST}
    2023/06/01 17:48:19 user: &{3 王五 password3 地址3 35 12345678903 70 部门1 2023-06-01 17:48:11 +0800 CST 2023-06-01 17:48:11 +0800 CST}
    2023/06/01 17:48:19 user: &{4 赵六 password4 地址4 28 12345678904 85 部门2 2023-06-01 17:48:11 +0800 CST 2023-06-01 17:48:11 +0800 CST}
    2023/06/01 17:48:19 user: &{5 钱七 password5 地址5 32 12345678905 75 部门1 2023-06-01 17:48:11 +0800 CST 2023-06-01 17:48:11 +0800 CST}
    
    

    搜索工具

    只需要下面一行代码即可完成单表的所有查询功能

    gplus.SelectList(gplus.BuildQuery[User](queryParams))
    

    例子:

    func main() {
      http.HandleFunc("/", handleRequest)
      http.ListenAndServe(":8080", nil)
    }
    
    func handleRequest(w http.ResponseWriter, r *http.Request) {
      queryParams := r.URL.Query()
      list, _ := gplus.SelectList(gplus.BuildQuery[User](queryParams))
      marshal, _ := json.Marshal(list)
      w.Write(marshal)
    }
    

    假设我们要查询username为zhangsan的用户

    http://localhost:8080?q=username=zhangsan
    

    假设我们要查询username姓zhang的用户

    http://localhost:8080?q=username~>=zhang
    

    假设我们要查询age大于20的用户

    http://localhost:8080?q=age>20
    

    假设我们要查询username等于zhagnsan,password等于123456的用户

    http://localhost:8080?q=username=zhangsan&q=password=123456
    

    假设我们要查询username等于zhagnsan,password等于123456的用户

    http://localhost:8080?q=username=zhangsan&q=password=123456
    

    假设我们要查询username等于zhagnsan,或者usename等于lisi的用户

    可以增加一个分组和gcond的条件查询来实现

    http://localhost:8080?q=A.username=zhangsan&q=B.username=lisi&gcond=A|B
    

    所有的单表查询我们都只需要一行代码即可。

    更多操作用法请查看:

    github.com/acmestack/g…

    如果你感兴趣的话,也不妨给个star。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论