Gopher 苦 ORM 久矣,发布个使用 rawsql 节省体力的包,使用姿势与标准库基本相同

2022-06-23 19:13:34 +08:00
 lesismal

初衷

这是前几天看到隔壁帖子吵得热闹,一时兴起写的,还没大规模测试,感兴趣的同学欢迎来 issue/pr 骚扰。

隔壁帖子: /t/859178

项目地址

示例代码

特点:

  1. 非 ORM ,仍然是标准库的姿势使用 rawsql
  2. 简单封装了标准库 sql ,Query 相关的方法增加了一个参数来接收结果,不再需要自己处理 rows
  3. 简洁干净,目前只使用标准库,无三方依赖

直接上代码吧:

db, err := sqlw.Open("mysql", "test:123qwe@tcp(localhost:3306)/sqlw_test", "db")
if err != nil {
      log.Fatal(err)
}

var dst examples.ModelForTest
err = db.QueryRow(&dst, `select * from sqlw_test.sqlw_test`)
if err != nil {
      log.Fatal(err)
}
log.Printf("dst: %v", dst)

var dsts []*examples.ModelForTest
err = db.QueryRow(&dsts, `select * from sqlw_test.sqlw_test`)
if err != nil {
      log.Fatal(err)
}
log.Printf("dst: %v", dsts )

db.Prepare|sql.Stmt, db.Begin|Tx 也类似,保持了标准库的简洁基础上省去了自己遍历 rows 去 scan 的麻烦,代码量节省很多

3305 次点击
所在节点    Go 编程语言
33 条回复
lesismal
2022-06-23 19:18:43 +08:00
@realpg @pastor 二位看下这种可否节省些体力
@jinzhu 也欢迎 gorm 大佬多多交流指导
lesismal
2022-06-23 19:20:02 +08:00
顺便推下自己另外两个库,详见旧帖或者我的历史帖:www.v2ex.com/t/794435
realpg
2022-06-23 19:26:16 +08:00
@lesismal #1
既有项目就 gorm 恶心着
未来项目公司的人闲着没事自己造轮子
架构思想从 go-pg 来
pansongya
2022-06-23 21:04:52 +08:00
但是这种混杂着也不好看懂吧 大佬能出个类似 mybatis 的吗?
lesismal
2022-06-23 21:59:06 +08:00
@pansongya 混杂是指 sql 和 sqlw 同时?还好吧,sqlw 把 DB 、Stmt 、Tx 这几个都包装了下,使用 db.Prepare/Begin 返回的是 sqlw 的 Stmt/Tx ,Query 相关的写起来就都简单了,我再考虑要不要增加个 Insert 、Update ,怎么设计能保持简单与优雅。

mybatis ,java 和 go 真的是繁冗与简洁的两个典型了,所以我估计不会去模仿任何一个 java 相关的方案了 /手动狗头 。。
mcfog
2022-06-23 23:26:01 +08:00
有和 jmoiron/sqlx 的对比吗?
dorothyREN
2022-06-23 23:29:19 +08:00
别的不说,就这一堆 err 看着就头大
lesismal
2022-06-24 10:28:12 +08:00
@mcfog #6
sqlx 我没太用,自己以前主要是使用标准库 rawsql 。sqlx 、gorm 、xorm 也都简单看过他们的文档教程、还是挺复杂的,相比于使用标准库 rawsql ,这些 sql 库学习成本更高、姿势有点多反倒需要去注意更多问题。
sql 的主要操作,就是增删改查,标准库的查询用 Query/QueryRow ,其他的用 Exec ,非常简洁明了,麻烦的地方就在于 Query 相关的 rows 到结果的 Scan 。
sqlw 把遍历 rows 去 Scan 这些省掉了,中间的一堆 if err 也省掉了。使用 rawsql 能让程序员保持对 sql 语句的功能、性能直观和敏感、减少或者避免 ORM 背后行为那些隐藏的细可能导致拼接出来的 sql 不是自己想要的、甚至出其他问题,而且虽然不是 ORM ,但是执行语句与结果映射到结构体一步到位,还是很省力了。

@dorothyREN #7
go 完全避免 if err 是不太现实的,sqlw 帮助去减少了 for rows.Next{ rows.Scan }这些地方的很多 if err 。
另外,很多人对 if err 抱怨,却没去想过,go 这样使用 if err 让他们的代码更健壮了。相比于其他一些语言用异常处理错误,go 把错误、异常各管各的其实更清晰,只是很多人“先入为主”,用习惯了以前的某种姿势或者框架提供的方式、不想去改变成更合理的方式罢了。
sky857412
2022-06-24 11:26:38 +08:00
不知道为啥,写 go 的人都哪么喜欢纯 sql ,企业级项目,维护 sql 真的不累吗?
maotao456
2022-06-24 11:49:20 +08:00
@sky857412 不累,反而更轻松,因为可以直接把 sql 复制出来运行测试
pastor
2022-06-24 12:11:43 +08:00
@lesismal 可以可以,我以后新项目里试试,这比 ORM 可舒服太多了
pastor
2022-06-24 12:18:50 +08:00
@sky857412
相比非 sql 于业务代码,sql 占比挺小的,而且 ORM 里你看不到 sql 的逻辑。

编程语言排行榜里,sql 甚至还前十呢,排名在 golang 和很多流行的语言前面呢。用 ORM 来对待 sql ,即使是 java 那些很成熟的 ORM ,也让我觉得是对 sql 的侮辱——人家是门语言,你们却像嫖客一样上来对人家一顿胡搞猛搞、连自己做了啥都不知道,然后还说 ORM 真香,真是对自己对 sql 都不负责,妥妥的渣男。。。

@maotao456 正解! ORM 党多数都是 cv 程序员、性能和服务稳定性啥的都不怎么在乎
sky857412
2022-06-24 14:08:11 +08:00
@pastor 一顿暴论
jam1024
2022-06-24 17:14:57 +08:00
怎么处理关联查询呢
lesismal
2022-06-24 21:02:00 +08:00
@pastor #12
其实其他那些 ORM 比较完善的语言,在做那些数据量不大的对性能没啥要求的项目时还可以的,比如学校的管理系统,公司的 OA ,这些通常单表都很小的没啥压力,用习惯了 ORM 的同行开发效率还是蛮高的

@jam1024 #14
比如 http 服务一个 routter handler:
1. 如果是只需要某个特定的表,直接用一些三方工具导出与表结构映射的 struct 拿来直接用就可以了,比如 model.User 结构体或者结构体数组拿来接收 Query 的结果
2. 涉及多表联查的,我们通常 router handler 文件里单独声明 struct 用于接收 rawsql 的字段,其实并不麻烦,而且通常规范点的项目,除了数据库的 model ,c/s 交互也是有规范的协议格式的,所以不管是 json 还是 pb 还是其他、不管是否联查、声明一个结构体这一步多数时候本来就已经存在于流程中了
jam1024
2022-06-24 22:34:06 +08:00
@lesismal 联查的实现是否会过于复杂,如果因为代码量过高又封装一个库出来,那不是当初不如直接用 ORM 库。然后还有个点就是这种模式上来得熟悉 sql ,join 之类的复杂的语句,别人 ORM 即使可能不太懂 sql 也能上来就用,出了问题然后再查询。再着是 sql 安全问题,ORM 库一般有封装解决这个问题,然后由社区抓漏洞,而如果纯 sql ,安全就得自己把握。
lesismal
2022-06-24 23:52:06 +08:00
@jam1024
我没预料到兄弟你认为 ORM 比 rawsql 难、ORM 比 rawsql 更安全。关于这两点,我的感觉刚好跟你相反。
lesismal
2022-06-24 23:54:16 +08:00
@jam1024 sql 与 ORM ,我觉得 @pastor 老兄 #12 这段虽然很逗,但确实又很贴切: “人家是门语言,你们却像嫖客一样上来对人家一顿胡搞猛搞、连自己做了啥都不知道,然后还说 ORM 真香,真是对自己对 sql 都不负责,妥妥的渣男。。。”
EscYezi
2022-06-25 02:42:11 +08:00
话说现在 ORM/sql 库没看到有用泛型的呢,像 Query row 方法用泛型把类型传进去还可以省一个参数+省一行声明
比如 dst,err:=db.QueryRow[examples.ModelForTest](“select …”)
liaohongxing
2022-06-25 08:31:35 +08:00
希望能增加一个工具方法 ,遇到 err 自动回滚, 签名为:
sqlw.Transaction() (err error) {}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/861739

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX