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

Spring Data Jpa 有更好的映射 SQL 语句的方法吗?

  •  
  •   abcbuzhiming · 2018-08-20 10:11:39 +08:00 · 4731 次点击
    这是一个创建于 2048 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近研究了一下 Spring Data Jpa 的文档。发现它的 ORM 方式似乎只有两种:
    1 Dao 层的接口,接口方法名以驼峰的方式分割成关键词,映射为 SQL 的语句
    2 通过 @query 注解手动编写类 sql 语句

    我觉得这两种方式,灵活度都很一般。假设一个表里有 3 个字段,我分别有三个地方用到了这个表,但是是分别的查询 3 个字段。这在 dao 层里得写 3 个接口。这实在是有点累赘,很多 orm 工具都是直接提供条件字段映射类的,不需要从方法名上去映射,灵活的多,一个方法能搞定任何字段的查询。

    是我打开 spring data jpa 的方式不对还是就只能这样?
    22 条回复    2018-08-21 09:56:29 +08:00
    qinxi
        2
    qinxi  
       2018-08-20 10:19:25 +08:00
    试试 JpaSpecificationExecutor 或者 QueryDSL
    lhx2008
        3
    lhx2008  
       2018-08-20 10:31:23 +08:00 via Android
    java 写接口语义化不是挺好,如果想不用接口的 orm,可以用 jooq
    u21t20o15
        4
    u21t20o15  
       2018-08-20 10:36:39 +08:00
    我同事用 Freemark 类似 MyBatis 的方式去做映射,一般需要很复杂的 SQL 才那样写
    linbiaye
        5
    linbiaye  
       2018-08-20 10:46:21 +08:00
    老哥,你的这个头像没穿 bra?
    swim2sun
        6
    swim2sun  
       2018-08-20 10:59:38 +08:00
    letitbesqzr
        7
    letitbesqzr  
       2018-08-20 11:13:02 +08:00
    QueryDSL +1 .. 我们引入了 spring data jpa ..但是 所有查询 基础接口 都封装自 QueryDSL,只是某些需要反射来排序 是用的 jpa
    CtrlSpace
        8
    CtrlSpace  
       2018-08-20 11:29:30 +08:00
    写几个接口而已,不算累赘吧。
    abcbuzhiming
        9
    abcbuzhiming  
    OP
       2018-08-20 11:29:52 +08:00
    @richard1122 首先谢谢,其次这个实现的还是过于简单。它只能附加字段条件,对注入 limit,group,order 就无能为力,而且无法嵌套,不过你这个提醒了我,我发现我文档看的不仔细,这部分文档上有,但是我看漏了

    @qinxi 感谢,我在文档上找到这两个了,QueryDSL 比较理想。但是 JpaSpecificationExecutor。。。怎么会有搞的如此复杂的实现?它有没有什么特长?比如 QueryDSL 做不了它能做的事情?光看功能他做的事情和 QueryDSL 差不多,但是 QueryDSL 比它直观和简单的多了


    @letitbesqzr 请教有啥是 QueryDSL 实现不了的?现在选型比较关注框架的弱点方面
    abcbuzhiming
        10
    abcbuzhiming  
    OP
       2018-08-20 11:31:27 +08:00   ❤️ 1
    @CtrlSpace 人的追求是无止境的,你用过 mybatis-plus 就明白了,如果你用过一些动态语言的 ORM 工具比如 ruby 的,你更会明白 java 的这些 ORM 工具局限在哪里
    skypyb
        11
    skypyb  
       2018-08-20 12:50:36 +08:00
    注入 entitymanager 自个写 SQL 啊...
    我遇到自带的注解解决不了的一般就自己手动写了。写 HQL 还是原生 SQL 都可以自己定
    rim99
        12
    rim99  
       2018-08-20 13:08:19 +08:00 via Android
    建议看下文档吧,记得有工厂方法可以传入类对象,定制返回类型的
    passerbytiny
        13
    passerbytiny  
       2018-08-20 14:58:58 +08:00   ❤️ 1
    首先纠正楼主两点:
    一、Hibernate、Jpa 和基于二者的 Spring Data Jpa,都没有“ Dao ”这个概念。
    二、既然用了 Spring Data Jpa,那么除非是是否旧的数据库,不应该考虑表、字段等任何数据库方便的概念。

    其次,楼主第二段的需求,我没看看明白。

    Spring Data Jpa 只是 Hibernate 的一个上层封装,通过约定加自动生成的方式,简化 Jpa/Hibernate 的编码。它本身并不是 ORM,也没有对使用方式做任何强制限制(你可以自由的添加自定义实现)。
    abcbuzhiming
        14
    abcbuzhiming  
    OP
       2018-08-20 15:13:17 +08:00
    @passerbytiny
    好吧,严谨一点说,spring data jpa 用 repository 来承担了 dao(或者叫 mapper)层的功能

    我没看懂“不应该考虑表、字段等任何数据库方便的概念”这句话,你不从数据出发如何建模呢?或者说你觉得正确的思考方式是什么样的呢?

    我第二段的需求,是希望能追求灵活性,举个例子,User 对象(表),在场景 1 下需要搜索 userName 字段,到场景 B 需要检索 nickName 字段,按照 spring data jpa 的文档,正统的做法你得在 UserRepository 准备两个 find 方法
    findByUserName(String userName)
    findByNickName(String nickName)

    这在我看来是比较麻烦的,因为很多其他 Orm 工具提交这样的做法,以下是伪代码:
    DYSQL dySQL = new DYSQL() //动态 sql 条件查询类生成
    dySQL.eq("列名",列值)..eq("列名",列值).groupy("XXXX").Order("XXX");
    select(dySQL);
    嗯,其实就是上面提到的 QueryDSL
    WispZhan
        15
    WispZhan  
       2018-08-20 15:55:35 +08:00 via Android
    @abcbuzhiming 看看 ddd。这些概念是 ddd 的
    passerbytiny
        16
    passerbytiny  
       2018-08-20 16:11:11 +08:00   ❤️ 1
    @abcbuzhiming Repository 不是 Dao,贫血领域模型用 Dao,常规领域模型用 Repository,它俩永远不会一起使用。

    领域驱动设计中的“存储库”的含义是:对象集合以及该集合的读写行为,形象一店的说,就是对象的仓库和仓库管理员。Spring 核心给的 Repository 的定义是:表示“存储库”,若是传统 Java EE 模式(这是好听的说法,说不好停的就是老旧的贫血模型模式),也可以表示 Dao。

    下面是 spring core 中 @Repository 的 javadoc 和谷歌翻译
    https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/stereotype/Repository.html

    表示带注释的类是“存储库”,最初由域驱动设计( Evans,2003 )定义为“用于封装模拟对象集合的存储,检索和搜索行为的机制”。
    实现传统 Java EE 模式(如“数据访问对象”)的团队也可以将此构造型应用于 DAO 类,但在此之前应注意理解数据访问对象和 DDD 样式存储库之间的区别。这个注释是一个通用的刻板印象,个别团队可能会缩小其语义并在适当时使用。
    如此注释的类 DataAccessException 在与 a 一起使用时有资格进行 Spring 翻译 PersistenceExceptionTranslationPostProcessor。带注释的类还阐明了它在整个应用程序体系结构中的作用,以用于工具,方面等。
    从 Spring 2.5 开始,这个注释也可以作为一个特化 @Component,允许通过类路径扫描自动检测实现类。
    passerbytiny
        17
    passerbytiny  
       2018-08-20 16:17:39 +08:00   ❤️ 1
    @abcbuzhiming “不应该考虑表、字段等任何数据库方便的概念”,是领域驱动设计的要求。领域驱动设计中,要求完全按照面向对象的方式去建模,数据库的部分由 Jpa 自动去处理。形象一点的说是:引入了 JPA 的实现( Hibernate 等)后,开发人员只需要设计 Java 类,数据库部分(包括结构和读写 SQL )由 JPA 自动处理。
    passerbytiny
        18
    passerbytiny  
       2018-08-20 16:21:48 +08:00   ❤️ 1
    @abcbuzhiming 你的这个需求,“场景 1 按照方式一搜索、场景 2 按照方式二搜索”是业务逻辑,不是 Dao/Repository 该干的事。

    在传统模式中,Dao 层提供 findByUserName(String userName) findByNickName(String nickName)两个方法,Service 层决定调用哪个方法。

    在 DDD 模式中,Repository 提供两个检索方法,领域服务或者应用服务决定调用哪个方法。
    passerbytiny
        19
    passerbytiny  
       2018-08-20 16:34:39 +08:00   ❤️ 4
    补一下 DDD 的软件架构。
    简单分层架构:由下到上依次是:模型层(含 Entity/Aggregation、Value Object、Repository )、Domain Service 层、Application Service 层。Domain Service 层是可选的,并且它仅仅是在调用关系上处于上层,业务关系上它跟模型层是平级的。

    依赖倒置架构:由下到上依次是:领域核心层( Entity/Aggregation、Value Object、Domain Service、Repository 接口部分)、Application Service 层、基础设施层( JPA、Hibernate、数据库、Domain Service 技术实现部分……)。此时的分层只表示业务依赖关系,与调用关系无关了。

    还有更复杂的架构。所有架构中都没有“ Dao ”,数据库也从来不会参与建模。
    wancaibida
        20
    wancaibida  
       2018-08-20 18:21:05 +08:00
    用 grails gorm
    WispZhan
        21
    WispZhan  
       2018-08-20 19:41:05 +08:00 via Android
    @passerbytiny 看来老哥也是个 ddd 爱好者
    abcbuzhiming
        22
    abcbuzhiming  
    OP
       2018-08-21 09:56:29 +08:00
    @passerbytiny
    “在 DDD 模式中,Repository 提供两个检索方法,领域服务或者应用服务决定调用哪个方法。”
    我看完了你的描述,但是我这里的需求是:领域服务希望 Repository 的方法能更灵活一点,因为在我的应用场景里 Repository 对应的是持久层关系数据库的访问,对一张表(对象)只提供一个方法就能完成大部分查询,是件很有用的特性。如果 Repository 必须用多个方法才能应对领域服务的需求,这会增加额外的开发成本
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5403 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 06:56 · PVG 14:56 · LAX 23:56 · JFK 02:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.