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

Java 除了 Mybatis,基于 Sql 的 Dao 还有更好的方案吗?

  •  
  •   abcbuzhiming · 2017-05-18 20:01:40 +08:00 · 12924 次点击
    这是一个创建于 2527 天前的主题,其中的信息可能已经有所发展或是发生改变。
    两年前用过 Mybatis,被坑了一大把,两年不敢再用,现在又要开始数据层选型,本人还是偏爱 sql 管理 dao 多点,不喜欢 hibernate,所以特来请教。也许是自己当年打开 Myabtis 的方式不对吧;当时有几个非常困扰我的关于 Mybatis 的地方:即使我用了 mybatis 的 mapper 生成工具,维护效率仍然很低,一个困境就是项目的数据库表在初期是经常变动的(哦不,应该说,是整个生命周期都在变动),一旦变动,对应表的 po 就变了,mybatis 里那个用来映射 po 的 resultMap 也得跟着变,于是你就得重新生产一遍这张 Mapper.xml。但是你的 Mapper.xml 里往往有你自己维护的 sql 语句( mybatis 生成的 mapper.xml 里自带的 sql 模板和接口并不能应对复杂情况,所以你仍然需要经常自己写新的 sql )。于是你就得备份旧的 mapper.xml,生成新的后你得从旧 xml 里把 sql 语句拷贝回去。这个过程真是太痛苦了。当时就有个想法,这该死的 resultMap 能否移到别的 xml 文件去,至少和放 sql 语句的 xml 分开啊,重新生成的时候不要互相影响啊。可惜没辙。另外 mybatis 基于 xml 的 sql 模板维护起来真的很头大,也没找到合适的工具。
    所以,我现在该咋办呢,mybatis 有没有生产力高一点的工具,或者有没有优秀一点的替代品?
    68 条回复    2018-10-14 14:00:21 +08:00
    uugklp
        1
    uugklp  
       2017-05-18 20:23:27 +08:00
    incompatible
        2
    incompatible  
       2017-05-18 20:54:22 +08:00
    姿势错了。
    resultMap 并非是必要的,你可以在<select/>里写 resultType="java bean fqcn",sql 里写 select *或者 select column_name as javaBeanPropertyName,这样 mybatis 就可以自动做影射。
    另外如果你的数据库表的 column_name 跟 java bean 的 propertyName 完全一致只不过前者用了 under_score 后者用了 camelCase,你还可以在 mybatis-config.xml 中指定 settings.setting.mapUnderscoreToCamelCase=true 来让 mybatis 自动完成 under_score 和 camelCase 的互相映射。
    changhe626
        3
    changhe626  
       2017-05-18 21:02:32 +08:00
    那个什么自己封装一个 JDBC 呗
    qiyuey
        4
    qiyuey  
       2017-05-18 21:09:35 +08:00
    用注解
    changdy
        5
    changdy  
       2017-05-18 21:11:01 +08:00   ❤️ 1
    感觉问题并不是处在 mybatis 上面,而是数据库的频繁改动吧.
    hcymk2
        6
    hcymk2  
       2017-05-18 21:19:42 +08:00
    感觉是个反的, 应该是模型的变化再反应到数据库表结构的改变。
    reeco
        7
    reeco  
       2017-05-18 21:22:29 +08:00 via iPhone
    对于这种需要频繁变动表结构的,hibernate 挺合适的。
    darrenfang
        8
    darrenfang  
       2017-05-18 21:32:56 +08:00 via iPhone
    一直用 hibernate,最近在学 spring data jpa
    abcbuzhiming
        9
    abcbuzhiming  
    OP
       2017-05-18 21:36:05 +08:00
    @incompatible 啊,谢谢,但是我还有个问题,如果我的数据库字段名和 java bean 的字段名是完全一致的话,那其实就 mapUnderscoreToCamelCase=true 都不用了,直接完全映射了是吗?
    abcbuzhiming
        10
    abcbuzhiming  
    OP
       2017-05-18 21:36:50 +08:00
    @changdy 除非你的公司是大型企业,从事的项目都是大型商业项目,否则我见没见过需求变动不剧烈的,越是中小型公司,越是互联网企业,需求变动越剧烈
    incompatible
        11
    incompatible  
       2017-05-18 21:59:29 +08:00
    @abcbuzhiming 没错,这种情况就不需要 mapUnderscoreToCamelCase 了。
    另外,实体变动频繁的话,更好的方式是开发阶段 spring-data-mongo + mongodb。上线时把 spring-data-mongo 切成 spring-data-jpa + rdbms 就好了。
    xliao
        12
    xliao  
       2017-05-18 22:06:27 +08:00 via iPhone
    spring data jpa+1, 有个项目在用,感觉很好用。原来一个项目在开发中发现 Mybatis 在一些场景下局限性,很后悔当时选择了它,然而现在换己经来不及了。
    CFO
        13
    CFO  
       2017-05-18 22:13:23 +08:00 via Android
    确实有这个问题 我解决的方式是不用 xml 全部用注解 然后不直接用生成的 mapper 自己写个 mapper 继承自动生成的 整个过程都使用自己写的这个 mapper 这样就算重新生成后 改动也会小很多
    nonesuccess
        14
    nonesuccess  
       2017-05-18 22:19:18 +08:00 via Android
    @CFO 注解是把 sql 写到 java 类里面的那种方法吗
    paragon
        15
    paragon  
       2017-05-18 22:41:53 +08:00
    mybatis 不是写好数据库基本 CRUD 都可以用生成器生成么?
    slixurd
        16
    slixurd  
       2017-05-18 22:42:06 +08:00
    @nonesuccess 是.在 Annotation 中直接写 SQL 即可
    遇到复杂的 SQL,用 SelectProvider,*Provider 之类的方法 workaround 一下就好了....
    除非特别复杂的 SQL,一般都不用 XML....
    WispZhan
        17
    WispZhan  
       2017-05-18 22:53:17 +08:00
    JOOQ ?
    abcbuzhiming
        18
    abcbuzhiming  
    OP
       2017-05-18 22:56:53 +08:00
    @paragon 基本 crud 压根没卵用,查询只能针对主键 id,很多场景都是针对特定字段的
    abcbuzhiming
        19
    abcbuzhiming  
    OP
       2017-05-18 22:58:59 +08:00
    @CFO 你的意思是注解 SQL 语句到 mapper 的接口方法上吗,然后你的 mapper 是动态生成的?
    fifman
        20
    fifman  
       2017-05-18 23:03:52 +08:00
    强烈推荐 spring data jpa。默认集成 hibernate,不需要你写 orm 映射配置,实体类通过注解直接和表关联。DAO 方法只需要定义接口,实现自动生成
    abcbuzhiming
        21
    abcbuzhiming  
    OP
       2017-05-18 23:15:10 +08:00
    @fifman 我就是不喜欢重 ORM,而且更喜欢 SQL,所以才不选 hibernate 的。
    abcbuzhiming
        22
    abcbuzhiming  
    OP
       2017-05-18 23:21:49 +08:00
    @incompatible 我心里就是不太愿意用重 ORM 工具啊,更喜欢 SQL 的,如果完全是 ORM 映射了,也就没啥意思了呢。
    另外我刚才想了,就算不用 resultMap 还是有问题,因为 mybatis 生成的 xml 里,insert 语句和 update 语句都是和表字段有关的,你改一次表,还是得重新生成 xml,但是我 xml 里有我自己编写的针对特定字段进行查询的 sql 语句,于是我又回到过去,我又得把旧 xml 备份一下,把旧 xml 我自己定义的语句拷贝到新 xml 去。有没有一种类似 ide 的工具,能建立一个针对 mybatis 的 xml 模板的项目,我把 sql 写好,它一键根据 sql 生成新的 xml,而且项目保存状态,我写的 sql 不会删除,下次改了表我改改 sql 再生成一次就行了,感觉一般的 mybatis 生成工具都是针对表本身,我需要自定义 sql 的时候就傻了
    incompatible
        23
    incompatible  
       2017-05-18 23:39:13 +08:00 via iPhone   ❤️ 2
    @abcbuzhiming 你扔掉这个鬼工具自己写 sql 或者自己写个简单的模板引擎只怕会更省事一些吧。。

    话说回来,sql 里就 select *好了啊,担心表字段太多 select *影响性能说明表的设计有问题,该拆就拆。
    Sql 写得太复杂也是设计有问题,等你并发上来了数据库服务器是很难做 scale out 或 scale up 提升性能的。RDBMS 么就拿他当个带事务的 entity store 就好了,永远只做单表查询(利于做缓存和 sharding ),复杂的 entity 关系在应用层写代码处理(利于 scale out )。复杂 sql 那是大厂们去 IOE 之前那个时代的风俗了。
    chocotan
        24
    chocotan  
       2017-05-18 23:39:55 +08:00
    mybatis 可以用注解的,不一定需要 xml
    laudukang
        25
    laudukang  
       2017-05-18 23:42:28 +08:00
    Spring-Data-Jpa
    hcymk2
        26
    hcymk2  
       2017-05-18 23:47:44 +08:00
    那干脆换语言算了, 还用什么 java.
    yidinghe
        27
    yidinghe  
       2017-05-18 23:55:30 +08:00 via Android
    本人的项目,用了多年了:
    http://git.oschina.net/yidinghe/hydrogen-dao
    miracleyao
        28
    miracleyao  
       2017-05-18 23:58:49 +08:00 via iPhone
    可以基于 JDBC 根据自己的需求封装一个,我们公司就是基于 JOSN 格式而不是 XML 的类似 mybatis 的一个插件
    crossoverJie
        29
    crossoverJie  
       2017-05-19 00:01:08 +08:00
    谈下目前我们项目的做法吧:

    依然用的是 mybatis 的 generator 工具来生成标准的 crud。
    对于标准的 crud 不能满足的情况自定义一个 xxxMapperExt.xml。之后自定义的 SQL 都写到这里边,对于数据结构发生改变对这个 xml 并不会覆盖依然该怎么用就怎么用。
    YzSama
        30
    YzSama  
       2017-05-19 00:57:43 +08:00 via iPhone
    @chocotan 对于复杂的查询也用注解?
    YzSama
        31
    YzSama  
       2017-05-19 00:58:08 +08:00 via iPhone
    @crossoverJie 求参考资料
    shot
        32
    shot  
       2017-05-19 01:16:14 +08:00
    spring-data-jpa,复杂查询上 QueryDSL

    如果被坑,九成几率是数据库表结构设计有问题。
    Cbdy
        33
    Cbdy  
       2017-05-19 07:33:25 +08:00 via Android
    mybatis.tk:通用 mapper ( jpa ),分页插件
    好用记得捐款
    mewushuang
        34
    mewushuang  
       2017-05-19 08:02:43 +08:00 via Android
    很早以前被 xml 坑过,前段时间研究 springboot 的时候好像看到 mybatis 出了 springboot 整合版,支持注解 sql
    watzds
        35
    watzds  
       2017-05-19 08:22:58 +08:00 via Android
    Mybatis generator, 在 eclipse 里,自动生成,自动合并自己写的和生成的部分。
    seelecpt
        36
    seelecpt  
       2017-05-19 08:41:06 +08:00   ❤️ 1
    @watzds 说的没错,用 eclipse 的插件,才能利用 eclipse 的文件管理特性进行合并。根据声称 xml 和 java 代码的注释自动进行重写,对数据库的字段进行重写。自己开发的部分进行合并。

    /**
    * @mbggenerated automatically generated by MyBatis Generator, do not modify.
    */


    <!--
    WARNING - @mbggenerated
    This element is automatically generated by MyBatis Generator, do not modify.
    -->
    lonenol
        37
    lonenol  
       2017-05-19 08:55:21 +08:00
    你可以增强一下生成工具,在生成工具的配置里维护所有的关系,并且支持增量更新,每次表有修改,重新生成一次就 ok 了
    phx13ye
        38
    phx13ye  
       2017-05-19 08:55:25 +08:00
    spring data jpa,很难写动态 sql 吧,Specifications 和 Querydsl 感觉都很难用。 @OneToMany @ManyToMany 也容易被滥用,建议还是 mybatis,Mybatis generator 不会动你手动写的部分 xml
    Michaelssss
        39
    Michaelssss  
       2017-05-19 09:02:06 +08:00
    = =如果 sql 和转换不通过自己的方法我就觉得很难学,普遍第三方为了场景完备搞出一堆概念,我很不喜欢,都是自己封装一下,把和 jdbc 通信扔给 SpringTemplate
    wupher
        40
    wupher  
       2017-05-19 09:27:04 +08:00
    之前我和楼主一样,也是偏向使用 SQL 来管理,不太喜欢太多依赖于 ORM 框架。(多年开发运营商养成的习惯)最近,给互联网公司做各种短平快的市场试验型项目,开发过程中数据库模型各种变,发现用 Mybatis 实在低效。一个简单的数据库映射层需要由多个 java 和设置文件来组成。现在,主要使用 GORM + SpringBoot,开发语言也由 java shift 到 groovy。一个数据库层仅需一个模型类即可。数据库由 domain 类直接生成。到上线前再由数据库导出建表 schema 手工优化(其实是为了去外键)。楼主可以试试。
    microhz
        41
    microhz  
       2017-05-19 09:27:42 +08:00
    mapper 生成工具能够避免开发效率问题,如果是自己写 SQL 可以单独出来一个 mapper,例如 UserMapper.xml,如果自己有一些联合查询或者自己写高性能 SQL 会去编写一个 UserRelateMapper.xml,这样原来的 User 表结构变化就不用担心自己写的 SQL 了
    v4ex4b
        42
    v4ex4b  
       2017-05-19 09:38:09 +08:00
    abcbuzhiming
        43
    abcbuzhiming  
    OP
       2017-05-19 10:42:04 +08:00
    @v4ex4b 其实这种方式也不太好,理论上来说,对某个表进行操作的所有 sql 都应该在一个 mapper 里,比较好维护,如果除了生成 mapper 之外的 sql 都放一个自己维护的 mapper,那么 service 层写业务的时候会遇到很尴尬的现象,前一行代码你还在用生成 mapper 的方法,下一行代码你得 new 一个自己维护的 mapper 里的方法。。。好坑啊
    birdccc
        44
    birdccc  
       2017-05-19 11:39:06 +08:00
    之前公司有大神自己封装了 jdbc,感觉比 mybatis 好用多了,直接操作实体类,然后映射表,但是就是多表 join 会麻烦, 我也不知道除了 mybatis 和自己封装,还有什么好的插件。
    debuggerx
        45
    debuggerx  
       2017-05-19 12:03:00 +08:00
    不知道是我理解有误还是姿势水平太低没有抓住要点:
    看前面没人提 jfinal,作为一个“写过后台的前安卓码农自称伪全栈”,我觉得 jfinal 的 Db + Record 模式操作数据库和模型非常爽啊,比 Myabtis 那种搞来搞去简单直观多了,修改维护也很轻松。。
    jych1224
        46
    jych1224  
       2017-05-19 12:28:04 +08:00
    aa6563679
        47
    aa6563679  
       2017-05-19 13:00:35 +08:00 via iPhone
    @debuggerx jfinal 那种模式不像是个静态语言了
    gowk
        48
    gowk  
       2017-05-19 13:05:03 +08:00
    Hibernate 和 Spring Data JPA 我都不喜欢,封装的太重,没有自由的感觉
    也许你说我水平不够。Good for you.
    debuggerx
        49
    debuggerx  
       2017-05-19 13:25:10 +08:00
    @aa6563679 对啊,所以它自己都自称拥有“动态语言的开发效率”,也或许是我平时也写一些 python 吧,感觉比较亲切。
    seeker
        50
    seeker  
       2017-05-19 13:59:12 +08:00
    楼主有没有看过 http://jdbi.org/
    blackboom
        51
    blackboom  
       2017-05-19 15:14:09 +08:00
    @debuggerx Jfinal Db + Record 其实很难维护的
    debuggerx
        52
    debuggerx  
       2017-05-19 15:51:52 +08:00
    @blackboom 不知道您说的是哪种场景?是说 mybatis 把 sql 片段放到外部文件一起管理而 Db + Record 是放到代码里么?这个问题的话我是觉得统一维护 sql 实在太费事了,因为毕竟 sql 还是代码逻辑的扩展,不看上下文直接维护 sql 不现实,所以宁愿在代码里的模式
    ppwangs
        53
    ppwangs  
       2017-05-19 16:05:07 +08:00
    如果没有特别复杂的 sql,jdbi 挺好用。
    mybatis 现在都开始搞注解啦,mapper 别用了
    li24361
        54
    li24361  
       2017-05-19 16:28:40 +08:00
    用 mybatis generator 生成并不会覆盖自己写的代码,
    需要覆盖的代码保留
    <!--
    @mbggenerated
    -->
    注解,不覆盖的删掉这个注解

    可以参考下我修改使用的
    https://github.com/li24361/mybatis-generator-core
    codeyung
        55
    codeyung  
       2017-05-19 16:47:24 +08:00
    paoding-rose-jade 可以 注解 /sql

    最近在用 springboot+mybatis
    sampeng
        56
    sampeng  
       2017-05-19 17:19:54 +08:00
    感觉核心问题还是数据库剧烈变化。。。偶尔加减 1-2 个字段什么的不管是什么都问题不大。。你要老颠覆数据库结构。不是自己给自己找不痛快么
    mosliu
        57
    mosliu  
       2017-05-19 17:19:56 +08:00
    spring data jpa 挺方便的
    特别是对应数据库要变的。手动改的少很多。
    tremblingblue
        58
    tremblingblue  
       2017-05-19 17:25:00 +08:00
    ebean,挺方便的
    tracymcladdy
        59
    tracymcladdy  
       2017-05-19 19:22:22 +08:00
    用 mongo+spring data jpa 没有表结构多爽
    caixiexin
        60
    caixiexin  
       2017-05-19 20:21:37 +08:00 via Android
    mybatis 现在可以完全不用 xnl 文件,直接在 @select 等注解里写 mapper 的 SQL,复杂的 SQL 再用 provider 类。
    大家说的 spring data jpa,用过几次,感觉像是轻量级的 hibernate ?
    caixiexin
        61
    caixiexin  
       2017-05-19 20:22:13 +08:00 via Android
    @caixiexin xnl 写错了,是 XML😂
    swolf119
        62
    swolf119  
       2017-05-19 21:13:16 +08:00
    一个是不用 xml
    一个是频繁变动的表不用 resultMap,直接用 resultType="com.xx.model.Xxx"
    sql 就是 SELECT col1 a,col2 b,col3 c from table where xxxxx
    cloudzhou
        63
    cloudzhou  
       2017-05-20 01:19:45 +08:00
    自己写 render 来渲染 xml,以前我就是这么做的
    micean
        64
    micean  
       2017-05-20 14:09:25 +08:00
    用新的类继承 POJO,只操作此子类,这样 POJO 自动生成不受干扰。
    另外就是像上面说的,自己管理好各种 xml 或者 mapper 了
    我自己是重新写了框架,支持泛型的 mapper,比如这样:
    public interface GenericMapper{
    @Update("............")
    <T> int insert(T t);
    }
    这样怎么改表也不会动太多东西
    liuzhen
        65
    liuzhen  
       2017-05-20 15:38:48 +08:00
    jfinal Model
    NUT
        66
    NUT  
       2017-05-21 18:51:08 +08:00
    考虑下 NOSQL 比如 mongodb 这种,经常变动的就适合 mysql 这种数据存储。
    v4ex4b
        67
    v4ex4b  
       2017-05-22 09:05:40 +08:00
    @abcbuzhiming 你姿势还是错了,mapper 可以是同一个,只要 namespace 相同即可
    FrankD
        68
    FrankD  
       2018-10-14 14:00:21 +08:00
    先挖个坟...
    这个问题是有优雅一点的解决方案的,直接抛弃 Mybatis 选择 Spring Data JPA、Hibernate 受限太多。
    例如有一个会员表叫 t_member,你自定义的 SQL 写在 MemberMapperSD.xml 中,增删改查的一般性 SQL 由工具自动生在 MemberMapper.xml 中,这样每次表结构改动,你只需要重新生成一遍覆盖 ***Mapper.xml ,***MapperSD.xml 再人工检查一遍即可。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5548 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 03:25 · PVG 11:25 · LAX 20:25 · JFK 23:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.