V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
gitrebase
V2EX  ›  程序员

大家喜欢用 ORM 还是直接写 SQL

  •  1
     
  •   gitrebase · 2023-12-29 12:50:20 +08:00 · 19485 次点击
    这是一个创建于 365 天前的主题,其中的信息可能已经有所发展或是发生改变。

    OP 主要用的 Java 和 Go ,但是感觉这俩主流语言的 ORM 框架( JPA 、GORM )都不如 C#、Python 的 ORM 好用( JOOQ 、ent 、XORM 感觉国内用的还是有点少),而 SQL / SQL builder ( JdbcTemplate 、sqlx )在动态条件查询时需要在代码里拼 SQL 字符串也有点🥚疼

    其实就是最近在玩 Spring 新出的 JdbcClient ( JdbcTemplate 的封装版),感觉在 Java 有多行字符串后,在 Java 代码里写 SQL 完全不是什么问题,而且也不用使用难用的 XML 去定义 resultMap (直接在 Java 里定义 record 或者 class 然后用构造器就可以了)

    public record User(Long id, String name, Integer sex) {
    }
    
    @GetMapping("/users/in")
    public Iterable<User> listInIds(@RequestParam List<Integer> ids) {
        return jdbcClient.sql("""
                SELECT *
                FROM `user`
                WHERE `id` IN (:ids)
                """)
                .param("ids", ids)
                .query(User.class)
                .list();
    }
    

    但是在碰到动态条件的 where 语句的时候,在 Java 代码里手搓 SQL 看着也很让人头大……这时候 MyBatis 提供的 dynamic SQL 就很好用了

    但真的不喜欢 XML……

    MyBatis-Plus 也了解过,但说不上来为什么,总是感觉不太喜欢这个库……

    155 条回复    2024-01-04 01:52:02 +08:00
    1  2  
    james122333
        101
    james122333  
       364 天前 via Android
    当然允许的情况是 sql 除了 xml 等外部设定当语言用的除外 除非用...
    用 sql 就像在下命令传参 直觉且少 orm 需要注意的细节
    orm 少个设定就找个半天了 除非这个 orm 够轻量没有一堆不必要的功能 即便如此 orm 短处就在那 动态 sql 语句就搞死人了 你也无法兼顾动态和直觉
    这篇感觉想钓鱼
    james122333
        102
    james122333  
       364 天前 via Android
    至于某些框架提供拼接 sql 语法的函数恰恰证明不是纯 orm
    题外话 laravel 还是快拿掉优雅这标签吧 不费什么资源力气才叫优雅 重的东西就不要叫优雅了
    netabare
        103
    netabare  
       364 天前 via iPhone
    ORM 能在出现例如 n+1 等常见问题的时候报错编译失败,直接写 sql 就没有这层检查了。
    zhuangzhuang1988
        104
    zhuangzhuang1988  
       364 天前
    肯定看情况啊,
    有不是非 A 即 B
    Immortal
        105
    Immortal  
       364 天前
    要不试试 sqlc
    msg7086
        106
    msg7086  
       364 天前
    ORM 也可以做多表联合查询,甚至可以根据具体情况做统一优化。
    比如有些 MySQL 的子查询性能有问题,ORM 可以改写成先查询出 ID 然后再用 IN(ID)另外做一次查询。
    再有比如说 MySQL 的大数 LIMIT 有性能问题,ORM 可以改写成先通过索引查出结果,然后再用 IN(ID)返回实际数据。

    你当然可以全手动优化,一个一个查询找出来再一个一个改。但我可以抽象成一个插件,插进 ORM 里整个系统就全改好了。

    上面这个 LIMIT 性能问题我之前自己的系统里刚遇到过。我自己做的一个 BT 站,几十万条记录,翻页翻得卡死。后来找到个 fast_page ,往 ORM 上加上,马上系统性能就上去了。我就加了这么一句:
    posts = posts.fast_page if params[:page].to_i > 50
    谁愿意写 SQL 谁去写,反正我懒。
    shijingshijing
        107
    shijingshijing  
       364 天前
    有了 ChatGPT ,再难的 SQL 也能写。
    james122333
        108
    james122333  
       364 天前 via Android
    @netabare

    这不是应该偷懒以及省资源就会主动想到解法的吗...
    TuringHero
        109
    TuringHero  
       364 天前
    一直习惯 JPA + Query DSL ,动态条件判断了用 Query DSL 拼就行
    james122333
        110
    james122333  
       364 天前 via Android
    @msg7086

    这与是否为 orm 无关吧 修改优化 sql 语句那是额外功能
    msg7086
        111
    msg7086  
       364 天前
    @james122333 抽象就是 ORM 的优势之一啊。抽象了以后就可以在更高维度进行优化了。
    zeroday
        112
    zeroday  
       364 天前
    常用 sql 都是自动生成的
    james122333
        113
    james122333  
       364 天前 via Android
    @msg7086

    那只是 parser 不同...
    bocchi1amos
        114
    bocchi1amos  
       364 天前
    感觉 orm 有点笨重,有时真不如我直接写 sql 。。
    joyhub2140
        116
    joyhub2140  
       364 天前
    有一说一,这个 JdbcClient 还真挺好用,特别是 IDEA 支持在 Java 代码里对 SQL 语句进行智能提示和高亮。

    数据库字段有变更,刷新一下连接,Java 代码里的 SQL 的 field 字段还支持变红警告。

    基本上可以抛弃 XML 写 SQL 了。
    rustz992
        117
    rustz992  
       364 天前
    不错我也是这个想法,别人的 sql 语句 有时候一看起来就感觉后面没法维护
    EscYezi
        118
    EscYezi  
       364 天前 via Android
    工作中 java 用 mybatis plus ,算是 orm 和 sql 混用,尽量用 mybatisplus 单表查询,不在 xml 里写 sql.但奈何总会有联表查询查询的业务。
    其实我更喜欢 jooq 那种,根据表结构生成 sqlbuilder ,然后用代码来写 type safe 的 sql
    sngxx
        119
    sngxx  
       364 天前 via iPhone
    写 sql 要把查出来的东西转成对象,一个一个字段搞能把人累死,还容易出 bug 。写工程重要的是实现,效率和稳定
    ipangpang
        120
    ipangpang  
       364 天前
    可以类比成 喜欢汇编还是喜欢 c 语言
    Int100
        121
    Int100  
       364 天前
    ORM 还是好用的
    msg7086
        122
    msg7086  
       364 天前
    @james122333 这里在讨论的本来不就是 ORM 的 Parser 部分吗?难道我们在讨论字段转对象这部分?
    说实话我没看懂你的意思。
    wonderfulcxm
        123
    wonderfulcxm  
       364 天前 via iPhone
    直接写 sql 挺好的啊,如果说一条 sql 手写起来麻烦,用 orm 拼出来只会更难。
    james122333
        124
    james122333  
       364 天前 via Android
    @msg7086

    orm 重点在物件映射 而不是整个 query string 都给 parse 了 这就是额外功能阿
    sun1991
        125
    sun1991  
       364 天前
    @flyingfz +1
    自从发现了 Dapper, 就一直用它到现在了, 并且由于它的影响, 做 JAVA 也喜欢用 JDBI.
    抛开公司开发规定不谈, 对于不会和不想学 SQL 的来说, ORM 是救星.
    ORM 应付解决简单问题 OK, 复杂情况只会再增加额外复杂度. 而且由于各个 ORM 实现不同, 切换比较麻烦. 相比之下 SQL 是标准化的, 各个实现相差不大.
    以前有过 MD 和 MP3 孰优孰劣的热烈讨论, 现在 MD 已经死的透透的了... 要是 ORM 真的如他宣传般好用, 几十年历史的 SQL 根本不会活到现在, 或者还被人拿出来谈论和 ORM 哪个好.
    cndenis
        126
    cndenis  
       364 天前
    这个问题还是要看情况,是做 CURD 还是做数据分析。数据分析动不动就几十上百行的 SQL ,转化为 ORM 的语法太痛苦。
    简单的 CURD 用 ORM 还是方便一些。
    我喜欢 Python 的 Peewee 这样的 SQL 拼装器式的 ORM 。
    我认为有些 ORM 太自以为是,所谓的 Code First 就是扯蛋的事。数据比代码更持久而且更有价值,做业务系统升级时,旧代码可以重构扔掉,旧数据一般都得保留兼容。做数据的基础上写代码才是正道,而不是把数据库当做代码的附属物。
    msg7086
        127
    msg7086  
       364 天前
    @james122333 但是你看看标题,问的是用 ORM 还是直接写 SQL ,所以谈的就是他的 parser 部分啊。
    msg7086
        128
    msg7086  
       364 天前
    @james122333 我又想了想。
    你说 ORM 在于对象映射。问题是对象映射的核心就是抽象,而优化起来简单本身就是抽象带来的好处。
    比如原本的 LIMIT 语句被 ORM 抽象成了分页组件,然后这个分页组件就可以被针对性附加优化。
    比如原本的 JOIN 语句被 ORM 抽象成了对象与对象之间的关系,然后这个关系也可以按照需求被针对性优化。有些数据库 JOIN 或者子查询更快,那就用 JOIN 或者子查询。有些则是分两次查询更快。有些场景下甚至需要联合查询多个数据库(比如合并查询 ElasticSearch 和 MySQL 等),这些都可以先抽象成对象,然后再在 ORM 内部针对性实现。
    ORM 本来就不是简单把返回值变成对象就完事了。
    jonsmith
        129
    jonsmith  
       364 天前
    之前用 gorm ,现在用的 Squirrel 。原生容易写错,一般用 orm 更好点。但是相比来说 laravel 、TP 的 orm 更好用
    superBearL
        130
    superBearL  
       364 天前
    Java 简单 sql MP ,复杂 SQLxml ,我喜欢结合起来用。MP 的 LambdaQuery 可以避免手写 SQL 打错字的烦恼
    wlm201219
        131
    wlm201219  
       364 天前
    jpa 感觉还可以,勉强用用,普通的连表、动态参数可以用 jpql ,复杂的老老实实用 sql
    zzhaolei
        132
    zzhaolei  
       364 天前
    gorm 本质也 sql 拼接,不算一个真正的 orm 。gorm 最好用的就是查询数据不需要一个个的 binding 了,通过反射直接写入 struct 、slice 、map 等。

    现在 go database/sql 也要加类似的机制,所以 gorm 的存在性又降低了一点。

    目前 go 的 orm 应该只有 ent 算是比较好的,假如改了表的字段,ent 能在编译时校验,gorm 是不行的
    changdy
        133
    changdy  
       364 天前
    @cndenis 正解 .一直都说 java 的 orm 太垃圾.所以才有 mybatis 这种工具的生存空间.
    可是每次我看我司动辄十多个查询条件,上百行的 sql 语句也都是心想 这东西真的放到 orm 中也未必轻松啊.

    更何况各种 orm 对方言支持比较弱..基本上达不到宣称的 能够不同数据库之间进行切换

    反过来思考一下 ..java 那么多用户选择 mybatis 也可能是因为 java 大部分时间都用来干了脏活累活..
    kenvix
        134
    kenvix  
       364 天前
    MyBatis 算个锤子的 ORM ,顶死就一个 SQL 模板引擎,Java 的 ORM 看看 JOOQ 吧
    kenvix
        135
    kenvix  
       364 天前
    私以为,没有自动扫表生成 POJO 、DAO 的库是不能称作 ORM 的
    gitrebase
        136
    gitrebase  
    OP
       364 天前
    @joyhub2140 #116 是的,用着很爽很流畅,但痛点就是复杂点的查询场景还得拼字符串……
    gitrebase
        137
    gitrebase  
    OP
       364 天前
    @zzhaolei 我感觉 GORM 只要别叫 ORM ,就没什么问题,还是很好用的;其实我也觉得把 GORM 当做一个很好用的 SQL Builder 就行,GORM 的很多封装后的东西都很好用,比如 Scopes 、CreateInBatch 、Upsert 之类的,还是能降低很多开发时间的
    Chieh
        138
    Chieh  
       364 天前
    EF 同时支持写 raw SQL ,因此用 ORM
    a1b2c3T
        139
    a1b2c3T  
       364 天前 via iPhone
    试试 mp 吧←_←,真的挺好使的
    tangqiu0205
        140
    tangqiu0205  
       364 天前
    @flmn 目前项目里用了几个月,只能说简单的查询还可以,select 想要加个聚合函数就不好搞了,另外 join 感觉也不好用。官方文档就根没写一样。现在新功能都用 gorm 写了。
    tangqiu0205
        141
    tangqiu0205  
       364 天前
    go 用的 gorm ,ent 太难用了,根据时间分表查询至今不知道怎么搞。
    11ssss
        142
    11ssss  
       364 天前
    个人角度讲我喜欢用 ORM 框架 JPA 没有之一,即优化了 hibernate 的复杂,又比 mybatis 优雅。而且基于对象的操作更适合在 Java 程序中使用。
    站在公司角度 我们目前在做的产品,要根据不同项目适配不同国产化数据库。选择硬编码写 SQL 这种方式也不合理。直接用 JPA 屏蔽了底层语法差异。
    pengtdyd
        143
    pengtdyd  
       364 天前
    个人见解:

    这个不能二选一吧,首先用 ORM 的前提是数据库物理模型要整理的非常清楚,业务逻辑理的特别顺才能事半功倍。否则如果是没有物理模型,表的关系非常乱,这种情况,我个人还是喜欢用 SQL ,不然特别复杂的 SQL ,都不知道怎么写,心智负担特别严重。
    chenzw2
        144
    chenzw2  
       364 天前
    通常都是混用,单表取值用 ORM ,复杂的用 SQL
    asuraa
        145
    asuraa  
       364 天前
    我喜欢 orm 而且喜欢 EntityFramewok Core 和 ActiveRecord
    james122333
        146
    james122333  
       364 天前 via Android
    @msg7086

    orm 运作不 parse query string
    orm 也并不需要优化你的请求才叫 orm
    我说的是这是额外的功能 并不是 orm 必需
    与抽象是否能够做到此事是两回事
    james122333
        147
    james122333  
       364 天前 via Android
    @msg7086

    况且很多 orm 实现的複杂语法也都是类同拼接 query string 直接拿来改来裸 sql 用也不无可能
    msg7086
        148
    msg7086  
       363 天前
    @james122333 不知道你到底想说什么。抽象才能带来额外的功能的可能性,支持额外的功能就是 ORM 的优势之一。如果你只是想翻来覆去抠字眼的话请不要再回复我了,纯粹是浪费你我的时间。
    james122333
        149
    james122333  
       363 天前 via Android
    @msg7086

    额外功能不是只有 orm 才有的优势 只是 orm 有做而已
    这并不是抠字眼 这种非 orm 常规的功能就不要拿来当 orm 必备的优势了 因为这么说纯 sql 封装的也可以实现这功能
    james122333
        150
    james122333  
       363 天前 via Android
    @msg7086

    实现额外功能与是否为对象无关 以这功能纯 sql 实现大可以用字典取代对象 也可以启动时分析一次即可
    f14g
        151
    f14g  
       363 天前 via Android
    外行只希望别被注入了就行🤔
    lucaslee
        152
    lucaslee  
       363 天前
    由于老项目就是 orm 的,所以就接着用了。一般场景 orm 的开发效率还是不错的,略复杂或者需要关注性能的可能需要手搓 SQL 了。但不推荐把 SQL 写代码里,比较难维护。
    OneMan
        153
    OneMan  
       363 天前
    jfinal 的 ActiveRecord 挺好用的
    troywinter
        154
    troywinter  
       360 天前
    复杂业务基本都是 sql 或者贴近 sql 的 orm mapping ,stackoverflow 也是自己搞了 dapper ,如果 ef 框架好用,他们也不用自己发明轮子了
    volvo007
        155
    volvo007  
       359 天前 via iPhone
    @chenqh 你的直觉没错。多对多的关系需要中间表,中间表.id + A.id + B.id 这样。这里中间表 id 最多会有 A 行数 x B 行数 个,等于中间表做了一个排列组合的中转站。如果是“多对多对多”,那么嵌套中间表就可以…… 我现在经常会和一个有 300 多张表的数据库打交道,天天看得眼花😂
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2734 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 12:23 · PVG 20:23 · LAX 04:23 · JFK 07:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.