V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
woodytang
V2EX  ›  程序员

关于 Java 和 Spring boot 开发体验的一些疑惑,请高手解答

  •  
  •   woodytang · 68 天前 · 3843 次点击
    这是一个创建于 68 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前写前端比较多,最近开始用 Spring boot 开发 api 使用的是 JPA Hibernate orm+jdk21 方案,我不知道为什么感觉国内很多人不喜欢这个 Hibernate ,但是我自己用下来感觉非常好,它最牛逼的是可以按照 Entity 生成数据库结构,非常智能,所以你只要把实体定义好,一切都 ok 了,很容易维护。 有个插件 JPA buddy ,非常好用,可以很好规范代码。 JPA 也可以自定义 sql ,很灵活,除了在转成 json 的时候,会遇到无限循环的问题,其他感觉都很好。 感觉 Spring boot 写后端,除了 JAVA 本身有点啰嗦,还有编译很浪费时间,其他都还蛮不错的。

    但是 JPA 通过 Entity 生成数据库的时候,为什么字段顺序和 Entity 是不一样的,是打乱的,,id 的位置会随机出现~~我槽,这就像要喝汤的时候飞进了一个苍蝇,我看网上有很多人说要 hack 一下,官方无解,但这个太离谱了。

    然后就是 CommandLineRunner ,我本来的需求是需要给项目 seed 一点初始化数据,这个 CommandLineRunner 只在启动的时候自动执行,不能通过 cli 命令执行,,泥马这个 CommandLineRunner 和 Command 一点关系都没有啊,我内个去,所以 seed 数据只能在 CommandLineRunner 加 if 条件。你去看人家 PHP laravel 都有 artisan cil 工具啊,这个可是天天都要用的,为啥你没有啊~~~你 Tomcat 都可以监听指令,为啥就不做一个监听 命令行指令的。 后来我看了一个 spring boot cli 的插件,结果完全不是这个概念。。

    为什么这么成熟的框架连这些基本都做不好啊谁可以告诉我一下

    然后我现在在看 liquidbase 和 flyway ,还是 flyway 吧,直接 sql 多优雅,liquidbase 那个语法不能忍受~~

    谁能告诉我怎么才能优雅的搞后端呢?

    34 条回复    2024-09-04 09:31:48 +08:00
    JYii
        1
    JYii  
       68 天前
    1.只有很多单表操作我才会倾向于 JPA 。复杂联表查询、CTE 子查询,sql 长的要命那种一般都在数据库客户端上调试写好了,直接搬到 mybatis xml 中。

    2.生产没有使用过 entity 去操作表结构,因为 DDL 操作都要提单过 DBA 操作。

    3.CommandLineRunner 接口定义就是应用启动后去执行自定义逻辑,此操作生命周期内只有一次。想自己调用,留个接口随便玩。

    4.没听过不知道

    5.哪有什么优雅不优雅,以前我喜欢复杂的设计模式,现在我只想一把梭完了回家
    Bingchunmoli
        2
    Bingchunmoli  
       68 天前 via Android
    见过几十张表连接或者复杂 sql 一两百行,就知道这些人是用不了 jpa 的,性能能劣化到没法使用
    woodytang
        3
    woodytang  
    OP
       68 天前
    1.只有很多单表操作我才会倾向于 JPA 。复杂联表查询、CTE 子查询,sql 长的要命那种一般都在数据库客户端上调试写好了,直接搬到 mybatis xml 中。
    请教一下,复杂查询这样写
    @Query("""
    SELECT c
    FROM Comment c
    WHERE c.parentId IN :parentIds
    ORDER BY c.createdAt DESC
    """)
    List<Comment> findByParentIds(List<Long> parentIds);
    不就可以自定义了吗,用 mybatis 有什么额外好处吗?


    2.生产没有使用过 entity 去操作表结构,因为 DDL 操作都要提单过 DBA 操作。
    撸个人项目,没 DBA ,主要想体验一下 spring boot ,否则可能会选用轻量化的方案

    3.CommandLineRunner 接口定义就是应用启动后去执行自定义逻辑,此操作生命周期内只有一次。想自己调用,留个接口随便玩。
    请教一下,是通过 http 调用吗?


    4.没听过不知道
    数据库版本管理,因为你有 DBA ,可能不用管这块

    5.哪有什么优雅不优雅,以前我喜欢复杂的设计模式,现在我只想一把梭完了回家
    :D ,我主要是想提供维护性,不想把不理解的东西写到代码里
    woodytang
        4
    woodytang  
    OP
       68 天前
    @Bingchunmoli 复制的主要是查询吧,查询可以自定义 sql ,jpa 主要管理实体和数据库对应一致很方便
    Nosub
        5
    Nosub  
       68 天前 via iPhone
    个人浅见:spring data jpa 和 mybatis 本质上是两种建模方式,一个从数据库表到 Java 对象,一个从 Java 对象到数据库表,换一种说法就是一个是面向对象,一个是面向集合,关系数据库本身是集合理论,而用 SQL 实现继承,多态,多重继承很复杂,很多人会用 SQL 实现同样的功能,但是他不知道在 Java 中的对应关系,还有我个人觉得 Hibernate 很复杂,就像很多人说的,写着写着自己就写不下去了,还是觉得 mybatis 写的舒服,简单说就是驾驭不了。
    woodytang
        6
    woodytang  
    OP
       68 天前
    @Nosub 说得太好了,我大概有点懂了,像我这样平时不怎么写 sql 的,JPA 的方式比较直观,因为它是更声明式,而不是面向过程的,ORM 主要维护业务实体关系,因为我无论是前段还是后端,都喜欢使用 domain 设计风格,所以这种面向业务的方案很适合我,但是如果遇到复杂的查询和业务关系,还是你说的面向集合,查询组合关系比较简单,我觉得可能是因为我是新手吧,还没遇到更复杂的场景
    sagaxu
        7
    sagaxu  
       68 天前
    国内不喜欢的是 HQL ,并非 Hibernate 本身,JPA 单表根据签名自动合成查询还是很好用的。HQL 最大的问题是,当你写出来的时候,脑子里还是人肉要翻译成 SQL ,然后才能判断这个语句是否高效,那么 HQL 解决了什么问题?并没有,还不如直接写 SQL 简单可控。

    再说 ORM ,一旦涉及到一对多甚至多对多的关系,那就不得不提 cache 和 lazy load 了,还有 1+n 查询,这些事情是自己做,还是交给 ORM 去做,仁者见仁,使用 ORM 就得很熟悉其工作机制,否则很容易写出损害性能的操作来。使用 ORM 提高的开发效率,也比较有限,偶尔由于不精通,踩到个坑,恐怕省下来的时间全都还回去。

    最后说 JPA ,80%以上的需求都可以由 JPA 实现,少数情况写个 SQL 也就搞定了。

    给运行中的程序发送管理指令,为什么不用 JMX 呢?如果只是每次都启动的命令行,你定义一个 bean ,然后 main 中根据参数决定初始化哪个 bean 不就好了?
    zhenjiachen
        8
    zhenjiachen  
       68 天前 via iPhone
    直接上 querydsl 配合 jpa ,比 mybatis 好用,flyway 最新版免费版只支持最新版数据库,不支持低一版本数据库,liquibase 可以配合 JPA buddy 直接生成文件,方便很多。
    开发的时候初始数据我觉得可以用单元测试,因为单元测试可以回滚事物和 mock ,而且还能提高代码健壮性
    higker
        9
    higker  
       68 天前
    建议使用 JDBC 手写,和 Servlet 来写 Web 项目。
    yechentide
        10
    yechentide  
       68 天前
    Doma2
    BBCCBB
        11
    BBCCBB  
       68 天前
    根据不同的条件拼接 sql 的时候 JPA 就难搞了.
    jackOff
        12
    jackOff  
       68 天前
    楼上说的基本正确:
    1-主要是企业项目不可能依附于某个人,肯定是有其他人接力维护
    2-用 jpa 的好处是可以省很多代码,坏处就是实力不行的家伙用这玩意搞多表关联偷懒,或者大佬开辟的 jpa 基石后续维护很容易维护成狗屎,其他狗屎尚且还有评鉴的余地,jpa 一旦出现 BUG 就是很难定位,那后人就得不断品尝的这坨越来越大的狗屎。
    3-而且企业开发代码目前版本要求是:
    1-代码简单易读(保证人员调度可接力)
    2-程序稳定易维护(禁止不打招呼炫技,用特殊算法请和项目其他成员解释,必须署名在内网留一篇可复现核实的技术文档),并且要开一次技术分享会来讲讲你这玩意解决了啥。这招出来后很多炫技刷 kpi 的就老实很多了,因为他得抽工作时间或者私人时间准备技术分享会了
    3-降低架构设计成本(老板也是人精,越来越觉得这点业务也犯得着用上那么多架构技术?)
    ikas
        13
    ikas  
       68 天前
    java 10 多年前最流行的框架是 SSH...H 就是 hibernate

    项目复杂度,开发时间,人员水平...无法平衡 导致它在国内用的少了.
    woodytang
        14
    woodytang  
    OP
       68 天前
    @sagaxu JMX 这个我研究一下,谢谢。
    如果只是每次都启动的命令行,你定义一个 bean ,然后 main 中根据参数决定初始化哪个 bean 不就好了?
    恰恰不是每次启动就执行的命令,而是随时可以执行的指令。脚本语言搞这个很常见
    woodytang
        15
    woodytang  
    OP
       68 天前
    @yechentide Doma2 看上去很不错的 query build ,我研究一下,谢谢!
    sagaxu
        16
    sagaxu  
       68 天前
    @woodytang 随时执行也是一样的,执行完就退出。用 @Lazy 注解要执行的命令的类,在入口类注入 ApplicationContext ,然后用 context.getBean 获取名字相应 bean 的时候就会执行那个命令。

    需要注意的是,像脚本一样运行时,需排除定时任务等不必要的服务,也不要启动 http 服务,这个可以通过 profile 来实现。
    billbob
        17
    billbob  
       68 天前
    你不会角色 spring 就只有 JPA 吧? 你可以 jdbc,jdbcClient,r2dbc,都很优雅.
    cppc
        18
    cppc  
       68 天前
    你要开发命令行工具可以看看 spring shell
    f0rb
        19
    f0rb  
       68 天前
    你要是个人项目的话,看看 DoytoQuery ,通过定义对象来控制生成的 SQL 语句,上面那个 Comment 的例子大概可以这样写:

    @SuperBuilder
    public class CommentQuery extends PageQuery {
    private List<Long> parentIdIn;
    }

    CommentQuery commentQuery = CommentQuery.builder().parentIdIn(list).sort("createdAt,DESC").build();
    List<Comment> comments = dataQueryClient.query(commentQuery);

    更复杂的查询示例还有 TPC-H 的 22 个用来对数据库进行性能测试的查询语句。
    之前推广的比较佛系,所以估计没什么人了解。
    前几天还在这里发了个帖子想问问有没有人搞过推广的,想先推下 Go 版本的试试。
    chihiro2014
        20
    chihiro2014  
       68 天前
    复杂的查询用 @Query 配合 projection
    stickchen
        21
    stickchen  
       67 天前
    @woodytang 查询条件是可选条件你咋写呢,xml 可以写 if 判断的
    woodytang
        22
    woodytang  
    OP
       67 天前
    @stickchen 我也是刚使用 spring boot 不久
    我想大概原理就是用字符串拼接吧,原生的 raw 查询,你可以把 where 那一部分 抽出来 用 if 来拼接;

    正规的做法应该是用 JPA Criteria API 吧,虽然我也没怎么用过;

    感觉 Hibernate 的 这两种查询方式,刚好和 laravel 的
    Query Builder:集合查询
    还有 Eloquent ORM:对象查询
    对上

    但是感觉 Hibernate 设计得更好,它和数据库对应得严丝合缝,只要你懂它的配置;
    prosgtsr
        23
    prosgtsr  
       66 天前 via iPhone
    用 hibernate ,创建了一个对象,保存到数据库。
    然后你修改了对象的一个字段,没有调用保存,你会发现数据库更新了。
    我觉得这种特性很让人难受,代码不再是一个所见即所得的东西。为什么我没有显式写更新他要替我更新呢?这对我造成了很大的心智负担,所以我不喜欢它。当然你可以说我对它的认知有问题,但即便如此我还是不喜欢它。
    chihiro2014
        24
    chihiro2014  
       66 天前
    @woodytang 这种做法非常耦合,不利于定制化处理
    RainCats
        25
    RainCats  
       66 天前
    @woodytang 注解里写 sql ,你是不是想"挨打"
    woodytang
        26
    woodytang  
    OP
       66 天前
    @prosgtsr 你要 save 啊,就相当于 commit ,否则不会触发数据库持久化的。ORM 的概念就是,对象是对象,也是数据库,你不要分开考虑,只要考虑对象就可以了。
    woodytang
        27
    woodytang  
    OP
       66 天前
    @RainCats 我是真的不知道写在 @Query 有什么问题啊,如果没条件判断的,一次性的复杂查询,写 @Query 不是很直观吗
    NikoXu
        28
    NikoXu  
       66 天前
    @f0rb 使用 querydsl 犯法吗 ?
    peakCa
        29
    peakCa  
       66 天前
    可以了解一下 jooq ,我们项目中就是使用这个 orm 框架,定义好表结构,自动生成数据库对象,支持 orm 操作也可以写 sql 查询。
    prosgtsr
        30
    prosgtsr  
       65 天前 via iPhone
    @woodytang 在搭配一些框架的时候,框架会自动帮你 commit 的
    f0rb
        31
    f0rb  
       65 天前
    @NikoXu 何出此言
    RainCats
        32
    RainCats  
       65 天前
    @woodytang 难道你用上有多行文本的 java 了?以及你维护过别人写在注解里的复杂 sql 吗?
    只考虑自己爽快不考虑别人迭代维护的痛苦
    f0rb
        33
    f0rb  
       65 天前
    @RainCats 楼主是 JDK21 啊
    RainCats
        34
    RainCats  
       64 天前
    @f0rb 抱歉了,是我摸鱼不够踏实,看东西不够详细
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3391 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:46 · PVG 18:46 · LAX 02:46 · JFK 05:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.