学习JPA笔记——构建复杂查询
本篇介绍两种 JPA 做复杂查询的方法,一个是用 SpringDataJPA 实现, 一个是用 Java EE 实现。
封面:同上篇,这次前景就是最高机密 Viper Zero。
嗯,没啥问题,每集一张,只是PS了
Foreword
JPA以及其他类似东西之间的关系
在进入正题之前还是稍微提一下这几个东西之间的关系。
首先JPA是一种规范,Java EE 中有把这种规范抽象出来的接口,具体实现是看用的什么框架,可以是 Hibernate 或者是 EclipseLink 等。
而这之中 Spring 又对 Java EE 中的接口再次封装,以更好地整合进 Spring 体系当中,但 SpringDataJPA 仍然是个抽象,具体实现仍然是看选型的框架。
但日常中,由于 SpringDataJPA 默认是 Hibernate 实现,所以一般场合基本相当于 Hibernate。
个人对于数据库复杂查询的理解或看法
对于联表这些事情我个人的感受来说是极为痛苦的,表面上可以不多此查询数据库,不查询多余数据,不需要程序做多次遍历。
其实在一些压力不大的场景中,这些都显得很无所谓。多次连接有缓存,多次遍历实际消耗也不大,多余数据实际上做 join 的时候就会拿过来,join 中加入条件也和第二次查询加入条件差不多。
但实际上最麻烦的,是当真正数据库压力上来了,这些操作都没有太大意义,最后还是会在数据库和程序此之间加入缓存,把数据库做的很多事情放到程序当中去做,尽量减低数据库压力。
而此时你就会发现之前做的联表查询之类的就像是外来物一样格格不入。
所以我对此也非常欣赏DDD的设计美感。
SpringDataJPA
SpringDataJPA 的复杂查询除了直接写 sql,按照规则定义 Repository 接口方法以外,还可以使用Specification做查询。
Specification
这是SpringDataJPA抽象出的一个接口,故并不一定通用于其他JPA的实现。
该接口重点在于toPredicate
方法,该方法将创建一个 where 语句对象。
1 |
|
这里我只做简要说明,以便于理解,仅供参考。
- root:
一般指实体类本身,包装成 Root 对象, 可由query.from(Post.class)得到Root<Post>
,Java EE 会提到。 - query:
sql语句对象,一般在此方法内部不做调用,Java EE 会给一些用于理解的调用。 - criteriaBuilder:
用于构建条件语句。
个人建议是不要管我说的这些,真要去理解就看源码注释,或者看下面 Java EE 的代码,更能够理解。
Getting Started
首先我们创建一个 Repository 接口,并继承JpaSpecificationExecutor<T>
以获得复杂查询的能力。
1 |
|
然后我们运用 java8 所带来的新特性,使用 lambda 构建一个匿名 Specification 的实现类,并实现 toPredicate 方法。
1 |
|
使用起来其实没什么困难,基本举一反三,其他的复杂查询我暂时没研究,主要是觉得可以避开用别的方法操作,或者提到程序中操作。
Java EE
实际上,SpringDataJPA 是对 Java EE 原本的 JPA 抽象再次包装了一层,所以这个可以说是原汁原味了。
Getting Stated
由于我主要使用 SpringDataJPA 所以摘抄了一段代码,出处。
1 |
|
- EntityManager
实体管理类,用于与持久化上下文进行互动,核心类。
其他几个 Root、CriteriaQuery、CriteriaBuilder 作用同上,毕竟spring只是做了封装。
看完上面代码,大致就能够了解清楚这几个类分别是怎么使用的了,总体来说其实比上面spring的实现所接触到的东西更加全面一些,也能够理解这几个类互相是怎么作用的了。