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

为何不选 Hibernate,非要 MyBatis?

  •  2
     
  •   dc2002007 · 2024-01-26 11:15:02 +08:00 · 16108 次点击
    这是一个创建于 387 天前的主题,其中的信息可能已经有所发展或是发生改变。

    ###一直不能理解 Hibernate 这么优秀的 orm 思想框架,为什么这么多项目还选择了在 xml 里写 sql 的 MyBatis ,求解惑?

    当然我首先是不能接受在 xml 里写 sql 这种行为的!
    orm 不够优秀吗?
    • 当然我知道,这个帖子一旦发出去,必定是会遭到嘲讽了,这个我已经做好了心理预期了
    第 1 条附言  ·  2024-01-26 14:06:49 +08:00
    综合评论来看,我总结一下:国内 java 程序员普遍对面对对象思想理解不深刻,导致 orm 思想很难灵活运用,故行业为了降低开发门槛,刻意选择了 ibatis 方向,这个也是社会培训等多方面造成的问题,jpa 还是主流,这是母庸置疑的,我们需要一个新陈代谢的过程,35 岁可能是这个代谢过程的重要节点。
    第 2 条附言  ·  2024-01-26 16:34:00 +08:00
    这个矛盾足够激烈,我今天赚了 3 个银币,目标达成,mybatis 是最好,我支持 mybatis
    第 3 条附言  ·  2024-01-29 09:12:19 +08:00
    各位宝宝们,这个帖子我下沉了,你们的讨论意见很鲜明,都是久经实战的好程序员,作为你们口中的 op ,我深感欣慰,v 站需要活力,共同努力~
    130 条回复    2024-06-13 10:46:44 +08:00
    1  2  
    nimble
        101
    nimble  
       2024-01-26 18:12:00 +08:00
    国产的 mybatis-plus 使用的方式跟 jpa 和 hibernate 一样,如果你的项目使用的是 mybatis-plus ,jpa 完全没问题,并且支持的功能更多,除了它放弃了恶心的 xml 写 sql 。
    wlm201219
        102
    wlm201219  
       2024-01-26 18:12:25 +08:00
    @BiChengfei 我觉得,从这个帖子的讨论和现在 35 岁就业危机来看,国内并不会从 mybatis 转向 jpa
    ZeroDu
        103
    ZeroDu  
       2024-01-26 18:15:46 +08:00
    @ZeroDu #100 甚至可以说:你用 Mybatis 这些还需要写 xml 的情况,放在 Hibernate 里面必然也是需要自定义 sql/hql 的
    aristotll
        104
    aristotll  
       2024-01-26 20:05:15 +08:00
    用 jooq 逃
    pigspy
        105
    pigspy  
       2024-01-26 20:30:15 +08:00
    作为一个 hibernate + jpa 的使用者本来想认真回答下的,不过这 lz 看上去是钓鱼的,真是建议 nuke 了
    izzy27
        106
    izzy27  
       2024-01-26 21:17:48 +08:00
    Hibernate 不好念,不利于传播
    jason31415926
        107
    jason31415926  
       2024-01-26 21:33:35 +08:00
    @wlm201219 可以聊聊国内计算机教育脱节的问题吗,谢谢
    jeesk
        108
    jeesk  
       2024-01-27 00:34:37 +08:00 via Android
    这么说吧, 一个报表连表 5-10 张, 你还会用 orm 吗? 谁不想偷懒直接用 orm ?
    jeesk
        109
    jeesk  
       2024-01-27 00:44:02 +08:00 via Android
    现在开源的项目多大多都是 mybatis plus , 各种泛型,还不如 jdbc template 呢,
    jeesk
        110
    jeesk  
       2024-01-27 00:46:28 +08:00 via Android
    国外的屎都是香的, 真的是。 国外 orm 用得多,国内用的少, 那么国内就是程序员不行。
    grpc web 就不遵守 rest 规范,grpc web 全是 post. 一大群人说香,google 就是正义, 这风气真是太舔了。
    morgan1freeman
        111
    morgan1freeman  
       2024-01-27 04:32:50 +08:00   ❤️ 3
    国情所致吧,国内的项目大多短平快,半年就要出成绩,甚至 2 个月就要出成绩,而且码农本身真的很便宜(相对国内的公司收入而言),一个项目再烂,再狗屎都能请到人来维护,像 JPA 这种 Model First 的框架当然不合适,远没有 mybatis 面向 db 表驱动的开发模式搞的快。

    要是美国 2000 美金就能雇佣工程师去吃屎,资本家怕是笑得合不拢嘴,做梦都能笑醒,软件工程?啥是软件工程? 2000 美金雇个大学生,让你在屎山里面 996 遨游不香么?这比 GPT 高级不知道多少的真人工智能,才 2000 美金在就中国能雇佣到一个入门的。

    讲一个真实的案例,我们系统里面有一个车辆模型,光是 status 状态就好几个, 审核状态,车辆可租售状态,催审状态 等一大堆的状态变量,而这些状态变量本身相互之间还有依赖。

    结果这些变量全部都在各个接口跟 job 里面来维护,本来这种状态变化最好的方式当然是维护一个状态机模式,在模型内部维护车辆状态,不至于代码逻辑失控。

    但是我们的现状就是类似 mybatis 这种,天然就是面向 db 的(虽然 mybatis 有提供一个表针对多个对象的转换服务,但是真的很少看到有人用,毕竟是个半残的 ORM ),几乎不存在逻辑内聚的需要,这个开发在 job 服务里面 query 出来 update 一下,那个开发在接口里面 query 出来 update 一下,代码多了,服务多了,基本上就失控了,第一版写的人很爽,因为一开始状态很少,变量也少,逻辑还没有分散在各个代码仓库(草台班子还用上了微服务,逻辑没有内聚,全靠人肉对代码进行跨仓库静态分析),基本上不会有什么思维负担,对于三版第四版维护的人来讲,简直比吃屎还难受,时间评估的多,还容易改错。

    说到底用 JPA 跟用 Mybatis 是两种截然不同的开发模式跟思维方式,一个系统里面 OLTP 的部分出错了,需要花费巨大的成本去定位问题,以及修复数据,并评估对生产数据带来的影响,成本极高。对于业务逻辑相对复杂的项目,建议使用 JPA 去好好建模分析的,减少业务变动对于后续维护者带来的心智负担。

    对于需求变化极快且复杂的 OLAP 需求,这种功能大多都是面向内部,用 SQL 怎么快怎么来,就算出错也没事,改改就好,而且我经常跟人讲,OLAP 就是要打破业务逻辑里面的 Model ,甚至用 es 来重新聚合 Model 的数据都没有问题,因为 OLAP 就算出问题,who care ?分析数据?根本不重要的东西。

    以我之前那个案例来讲,有一个哥们因为车辆状态太复杂,帮业务下线一匹数据,job 维护车辆的逻辑写错了,导致生产上几千辆车 没法进行租售,直接就是生产重大事故,要是做个报表联几个表出一个后台页面,就算是错了又能怎样?糊弄一下就过去了。
    GoRoad
        112
    GoRoad  
       2024-01-27 11:06:01 +08:00
    很奇怪,翻了一下帖子 大家都是在友好讨论,反而 op 的 append 有些破防了,我认为 op 这是在恶意引战不成破防了,@Livid 恶意引战
    chuck1in
        113
    chuck1in  
       2024-01-27 12:08:40 +08:00
    hibernate 除了本身的 ORM 概念以外,其实还有一些其他的概念,会有一些心智负担,有些可能会不太喜欢这个概念。
    mybatis 我想胜在简单吧,在东亚比较流行。

    最后我建议也可以试试 JPA 和 Mybatis 之外的第三种选择:JOOQ
    https://www.v2ex.com/t/1007609#reply12
    chuck1in
        114
    chuck1in  
       2024-01-27 12:16:38 +08:00
    @aristotll 同样支持 jooq + 1
    chuck1in
        115
    chuck1in  
       2024-01-27 12:20:10 +08:00
    @morgan1freeman 2000 美金恐怕雇佣的还不止入门的哦,雇个接近高级的,运气好雇个高级也不是不可能的。
    Dragonphy
        116
    Dragonphy  
       2024-01-27 13:11:01 +08:00
    jpa 能不能做到 mybatis-plus 那样清晰的日志,一堆 alias t.x,t.x 找半天才知道是哪张表
    totoro52
        117
    totoro52  
       2024-01-27 14:56:18 +08:00   ❤️ 1
    看了你的 append 好了 黑名单见, 流量赚了马跑了
    yoloMiss
        118
    yoloMiss  
       2024-01-27 20:49:12 +08:00
    我曾经见过把 hibernate 又封了一层的项目,用起来跟一坨大便一样。真的是会的人简单,不会的人瞎几把搞啊。
    dyv9
        119
    dyv9  
       2024-01-28 08:10:55 +08:00 via Android
    @yooomu 最近特意把我接手的 3 个项目换到 Java 21 编译级别,开发中观察我们的项目对 Java 21 的兼容性,我相信我啥也不需要改就可以跑起来。
    gowk
        120
    gowk  
       2024-01-28 09:35:47 +08:00
    @morgan1freeman #111 感谢分享,太 tm 真实了!
    jinsongzhao
        121
    jinsongzhao  
       2024-01-28 15:27:55 +08:00
    说点有用的吧,hibernate 一套代码兼容多种数据库,适合做产品。多表关联和本地 SQL 等等,复杂,但是也能做,并且多了一些 HQL 的特有功能,这些功能是为了方便某些特殊情况的,绕那么大一卷坚持 ORM ,总要有某个重要优点。最后,JPA 是借鉴 Hibernate 的,或者是说 Hibernate 是 JPA 的试验基地,设计者本身也是 Java 标准的制定者,所以更有权势,技能寿命会更长久。
    pocketz
        122
    pocketz  
       2024-01-28 19:26:59 +08:00
    darrenfang
        123
    darrenfang  
       2024-01-28 20:51:11 +08:00 via iPhone
    @leohuangsulei 公司项目用 mybatis plus ,2 个条件以内的查询我是支持将查询条件用作方法名。
    darrenfang
        124
    darrenfang  
       2024-01-28 20:55:50 +08:00 via iPhone
    公司项目用的 mybatis plus ,有很多人直接用 QueryWrapper 写查询条件,更让人头疼🤕️
    shitshit666
        125
    shitshit666  
       2024-01-28 22:00:30 +08:00
    Java 那群老顽固多的很,你让他改变点什么,比杀了他还难受。
    byte10
        126
    byte10  
       2024-01-29 09:49:27 +08:00
    @Umenezumi
    @x66
    这一点其实我挺同意的,本身面向过程开发 就是比较舒服,快速,符合人理解的方式。面向对象确实比较难一些,这个真没说错,大多数都还是 mvc 模式,而不是 struts2 。
    28Sv0ngQfIE7Yloe
        127
    28Sv0ngQfIE7Yloe  
       2024-01-29 10:59:11 +08:00
    @shitshit666
    你也是挺能扯的
    ForMrFang
        128
    ForMrFang  
       364 天前
    两者各有优缺点.取决于业务或数据结构. 不过我推荐可以尝试一下 mybatis flex.
    SkyLine7
        129
    SkyLine7  
       362 天前
    现在我们都用 mybatis 注解写了,不用 xml
    vishun
        130
    vishun  
       248 天前
    原先也很倾向纯 ORM ,但是现在反而越来越觉得复杂 sql 还是原生的更直观,可以参考这个[根据条件分页查询用户列表]( https://gitee.com/mybatis-flex/mybatis-flex/issues/I90V7G#note_25272825_link),我贴过来:
    ```
    /**
    * 根据条件分页查询用户列表
    *
    * @param searchReq 用户信息
    *
    * @return 用户信息集合信息
    */
    @Override
    @DataScope(deptAlias = SysDept.TABLE_ALIAS, userAlias = SysUser.TABLE_ALIAS)
    public Page<SysUser> selectUserList(PageAdapter<SysUser> pageAdapter, final SysUser searchReq) {
    final QueryWrapper queryWrapper = queryChain()
    .select(SYS_USER.DEFAULT_COLUMNS, SYS_DEPT.DEPT_NAME, SYS_DEPT.LEADER)
    .from(SYS_USER.as(SysUser.TABLE_ALIAS))
    .leftJoin(SYS_DEPT).as(SysDept.TABLE_ALIAS).on(SYS_USER.DEPT_ID.eq(SYS_DEPT.DEPT_ID))

    .eq(SysUser::getDelFlag, UserConstants.NORMAL) // 是否删除: 否
    .eq(SysUser::getUserId, searchReq.getUserId(), IdUtils.isIdValid(searchReq.getUserId())) // 用户 ID
    .like(SysUser::getUserName, searchReq.getUserName(), StrUtil.isNotBlank(searchReq.getUserName())) // 用户名称
    .eq(SysUser::getStatus, searchReq.getStatus(), StrUtil.isNotBlank(searchReq.getStatus())) // 用户状态
    .like(SysUser::getPhonenumber, searchReq.getPhonenumber(), StrUtil.isNotBlank(searchReq.getPhonenumber())) // 手机号码
    .ge(SysUser::getCreateTime, searchReq.getParams().getBeginTime(), Objects.nonNull(searchReq.getParams().getBeginTime())) // 创建时间开始
    .le(SysUser::getCreateTime, searchReq.getParams().getEndTime(), Objects.nonNull(searchReq.getParams().getEndTime())) // 创建时间结束
    .and(qw -> qw.eq(SysUser::getDeptId, searchReq.getDeptId()) // 部门过滤
    .or(SYS_USER.DEPT_ID.in(QueryWrapper.create().select(SYS_DEPT.DEPT_ID)
    .from(SYS_DEPT)
    .where(QueryMethods.findInSet(QueryMethods.number(searchReq.getDeptId()), SYS_DEPT.ANCESTORS).gt(0)))),
    IdUtils.isIdValid(searchReq.getDeptId()))
    // 数据权限
    .and(qw -> qw.where(searchReq.getParams().getDataScope()), searchReq.getParams().hasDataScopeFilter());

    return getMapper().paginate(pageAdapter.getPage(), queryWrapper);
    }
    ```
    如果用 xml 差不多是这样:
    ```
    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
    select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password,
    u.sex,u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time,
    u.remark,
    u.show_tag,
    d.dept_name, d.leader
    from sys_user u
    left join sys_dept d on u.dept_id = d.dept_id
    where u.del_flag = '0'
    <if test="searchValue != null and searchValue != ''">
    AND (
    u.user_name like concat('%', #{searchValue}, '%')
    OR u.nick_name like concat('%', #{searchValue}, '%')
    )
    </if>
    <if test="userId != null ">
    AND u.user_id = #{userId}
    </if>
    <if test="userName != null and userName != ''">
    AND u.user_name like concat('%', #{userName}, '%')
    </if>
    <if test="status != null and status != ''">
    AND u.status = #{status}
    </if>
    <if test="phonenumber != null and phonenumber != ''">
    AND u.phonenumber like concat('%', #{phonenumber}, '%')
    </if>
    <if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
    AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
    </if>
    <if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
    AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
    </if>
    <if test="deptId != null and deptId != 0">
    AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE FIND_IN_SET
    (#{deptId},ancestors) ))
    </if>
    <!-- 数据范围过滤 -->
    ${params.dataScope}
    </select>
    ```
    个人感觉 xml 方式反而更加直观看出查询的字段和检索条件。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2864 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:46 · PVG 20:46 · LAX 04:46 · JFK 07:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.