QueryDSL-JPA

QueryDSL简介

官网

1 QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。
2 Querydsl可以通过一组通用的查询API为用户构建出适合不同类型ORM框架或者是SQL的查询语句,也就是说QueryDSL是基于各种ORM框架以及SQL之上的一个通用的查询框架。
3 借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA,JDO,SQL,Java Collections,RDF,Lucene,Hibernate Search。

创建项目

首先对于queryDSL有两个版本,com.mysema.querydsl和com.querydsl,前者是3.X系列后者是4.X系列,这里使用的是后者.

第一步:Maven引入依赖

<!--query dsl-->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<!--query dsl end-->

第二步:加入插件,用于生成查询实例

<!--该插件可以生成querysdl需要的查询对象,执行mvn compile即可-->
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>

执行mvn compile之后,可以找到该target/generated-sources/java,然后IDEA标示为源代码目录即可.

实体类

城市类:

@Entity
@Table(name = "t_city", schema = "test", catalog = "")
public class TCity {
//省略JPA注解标识
private int id;
private String name;
private String state;
private String country;
private String map;
}

旅馆类:

@Entity
@Table(name = "t_hotel", schema = "test", catalog = "")
public class THotel {
//省略JPA注解标识
private int id;
private String name;
private String address;
private Integer city;//保存着城市的id主键
}

单表动态分页查询

Spring Data JPA中提供了QueryDslPredicateExecutor接口,用于支持QueryDSL的查询操作,这样的话单表动态查询就可以参考如下代码:

        //查找出Id小于3,并且名称带有`shanghai`的记录.

        //动态条件
QTCity qtCity = QTCity.tCity;
//该Predicate为querydsl下的类,支持嵌套组装复杂查询条件
Predicate predicate = qtCity.id.longValue().lt(3)
.and(qtCity.name.like("shanghai"));
//分页排序
Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"id"));
PageRequest pageRequest = new PageRequest(0,10,sort);
//查找结果
Page<TCity> tCityPage = tCityRepository.findAll(predicate,pageRequest);

多表动态查询

QueryDSL对多表查询提供了一个很好地封装,看下面代码:

    /**
* 关联查询示例,查询出城市和对应的旅店
* @param predicate 查询条件
* @return 查询实体
*/
@Override
public List<Tuple> findCityAndHotel(Predicate predicate) {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity,QTHotel.tHotel)
.from(QTCity.tCity)
.leftJoin(QTHotel.tHotel)
.on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue()));
//添加查询条件
jpaQuery.where(predicate);
//拿到结果
return jpaQuery.fetch();
}

城市表左连接旅店表,当该旅店属于这个城市时查询出两者的详细字段,存放到一个Tuple的多元组中.相比原生sql,简单清晰了很多.

那么该怎么调用这个方法呢?

    @Test
public void findByLeftJoin(){
QTCity qtCity = QTCity.tCity;
QTHotel qtHotel = QTHotel.tHotel;
//查询条件
Predicate predicate = qtCity.name.like("shanghai");
//调用
List<Tuple> result = tCityRepository.findCityAndHotel(predicate);
//对多元组取出数据,这个和select时的数据相匹配
for (Tuple row : result) {
System.out.println("qtCity:"+row.get(qtCity));
System.out.println("qtHotel:"+row.get(qtHotel));
System.out.println("--------------------");
}
System.out.println(result);
}

这样做的话避免了返回Object[]数组,下面是自动生成的sql语句:

select
tcity0_.id as id1_0_0_,
thotel1_.id as id1_1_1_,
tcity0_.country as country2_0_0_,
tcity0_.map as map3_0_0_,
tcity0_.name as name4_0_0_,
tcity0_.state as state5_0_0_,
thotel1_.address as address2_1_1_,
thotel1_.city as city3_1_1_,
thotel1_.name as name4_1_1_
from
t_city tcity0_
left outer join
t_hotel thotel1_
on (
cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
)
where
tcity0_.name like ? escape '!'

多表动态分页查询

分页查询对于queryDSL无论什么样的sql只需要写一遍,会自动转换为相应的count查询,也就避免了文章开始的问题4,下面代码是对上面的查询加上分页功能:

    @Override
public QueryResults<Tuple> findCityAndHotelPage(Predicate predicate,Pageable pageable) {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity.id,QTHotel.tHotel)
.from(QTCity.tCity)
.leftJoin(QTHotel.tHotel)
.on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue()))
.where(predicate)
.offset(pageable.getOffset())
.limit(pageable.getPageSize());
//拿到分页结果
return jpaQuery.fetchResults();
}

和上面不同之处在于这里使用了offset和limit限制查询结果.并且返回一个QueryResults,该类会自动实现count查询和结果查询,并进行封装.

调用形式如下:

    @Test
public void findByLeftJoinPage(){
QTCity qtCity = QTCity.tCity;
QTHotel qtHotel = QTHotel.tHotel;
//条件
Predicate predicate = qtCity.name.like("shanghai");
//分页
PageRequest pageRequest = new PageRequest(0,10);
//调用查询
QueryResults<Tuple> result = tCityRepository.findCityAndHotelPage(predicate,pageRequest);
//结果取出
for (Tuple row : result.getResults()) {
System.out.println("qtCity:"+row.get(qtCity));
System.out.println("qtHotel:"+row.get(qtHotel));
System.out.println("--------------------");
}
//取出count查询总数
System.out.println(result.getTotal());
}

生成的原生count查询sql,当该count查询结果为0的话,则直接返回,并不会再进行具体数据查询:

select
count(tcity0_.id) as col_0_0_
from
t_city tcity0_
left outer join
t_hotel thotel1_
on (
cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
)
where
tcity0_.name like ? escape '!'

生成的原生查询sql:

select
tcity0_.id as id1_0_0_,
thotel1_.id as id1_1_1_,
tcity0_.country as country2_0_0_,
tcity0_.map as map3_0_0_,
tcity0_.name as name4_0_0_,
tcity0_.state as state5_0_0_,
thotel1_.address as address2_1_1_,
thotel1_.city as city3_1_1_,
thotel1_.name as name4_1_1_
from
t_city tcity0_
left outer join
t_hotel thotel1_
on (
cast(thotel1_.city as signed)=cast(tcity0_.id as signed)
)
where
tcity0_.name like ? escape '!' limit ?

查看打印,可以发现对应的city也都是同一个对象,hotel是不同的对象.

QueryDSL-JPA的更多相关文章

  1. Spring Data JPA教程, 第五部分: Querydsl(未翻译)

    The fourth part of my Spring Data JPA tutorialdescribed how you can implement more advanced queries ...

  2. JPA 复杂查询 - Querydsl

     添加依赖 <!--query dsl --> <dependency> <groupId>com.querydsl</groupId> <art ...

  3. SpringBoot12 QueryDSL01之QueryDSL介绍、springBoot项目中集成QueryDSL

    1 QueryDSL介绍 1.1 背景 QueryDSL的诞生解决了HQL查询类型安全方面的缺陷:HQL查询的扩展需要用字符串拼接的方式进行,这往往会导致代码的阅读困难:通过字符串对域类型和属性的不安 ...

  4. SpringBoot12 QueryDSL02之利用QueryDSL实现多表关联查询

    1 业务需求 有的系统业务逻辑比较复杂,存在着多表关联查询的的情况,查询的内容不仅仅是单张表的的内容而是多张表的字段组合而成的,直接使用SplringDataJPA实现是比较复杂的,但是如果使用Que ...

  5. SpringDataJPA+QueryDSL玩转态动条件/投影查询

    在本文之前,本应当专门有一篇博客讲解SpringDataJPA使用自带的Specification+JpaSpecificationExecutor去说明如何玩条件查询,但是看到新奇.编码更简单易懂的 ...

  6. 为什么放弃Hibernate、JPA、Mybatis,最终选择JDBCTemplate

    一.前言 因为项目需要选择数据持久化框架,看了一下主要几个流行的和不流行的框架,对于复杂业务系统,最终的结论是,JOOQ是总体上最好的,可惜不是完全免费,最终选择JDBC Template. Hibe ...

  7. springboot2.X 使用spring-data组件对MongoDB做CURD

    springboot2.X 使用spring-data组件对MongoDB做CURD 使用背景 基于快速开发,需求不稳定的情况, 我决定使用MongoDB作为存储数据库,搭配使用spring-data ...

  8. Spring Data JPA进阶——Specifications和Querydsl

    Spring Data JPA进阶--Specifications和Querydsl 本篇介绍一下spring Data JPA中能为数据访问程序的开发带来更多便利的特性,我们知道,Spring Da ...

  9. 如何在Spring Data JPA中引入Querydsl

    一.环境说明 基础框架采用Spring Boot.Spring Data JPA.Hibernate.在动态查询中,有一种方式是采用Querydsl的方式. 二.具体配置 1.在pom.xml中,引入 ...

  10. Spring Boot (六): 为 JPA 插上翅膀的 QueryDSL

    在前面的文章中,我们介绍了 JPA 的基础使用方式,<Spring Boot (三): ORM 框架 JPA 与连接池 Hikari>,本篇文章,我们由入门至进阶的介绍一下为 JPA 插上 ...

随机推荐

  1. [Beta]Scrum Meeting#3

    github 本次会议项目由PM召开,时间为5月8日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 改进界面 改进界面 bh ...

  2. wx.request 请求与django

    wx.request 1.wx.request相当于ajax请求,和django后台进行交互 官方文档:https://developers.weixin.qq.com/miniprogram/dev ...

  3. Vue日常开发问题

    1.sh: webpack-dev-server: command not found 我的公众号:

  4. PHP获取指定分钟数的下一个整数倍

    2019-6-11 11:51:03 星期二 情景: 要定时发送邮件, 邮件数据入表时就记录下其待发送时间, 然后crontab是每分钟扫描邮件表, 找出当时那一分钟需要发送的邮件 举例: 假如有一种 ...

  5. json 格式化处理工具

    json 格式化处理工具 用于JSON的快速命令行处理工具,简单无依赖. 我这边列举一些最常用的: 调试 http 请求时打印格式化后的数据 格式化本地或或流中的数据 获取 json 的键值或进行执行 ...

  6. [No000019A]IDEA 设置手册

    [No000019A]idea设置手册.rar IDEA 设置手册 IDEA 设置手册 plugin lgnore files and folesrs 代码管控 程序框架 部署方式 useless 3 ...

  7. Vmvare v12下搭建Ubuntu操作系统-18.04-desktop-amd64.iso镜像环境

    1.选择[典型],点击下一步.  2.找到ubuntu镜像文件所在位置,如图所示:  3.配置用户信息  4.设置安装位置  5.磁盘尽量大一些,笔者设置40g  6.自定义修改硬件信息  7.内存建 ...

  8. SonarQube + Jenkins代码审查环境安装文档 v1.2

    1. 安装SonarQube 1.1. 下载 下载地址:https://www.sonarqube.org/downloads/ 本次使用安装包为:sonarqube-7.4.zip 需要提前准备jd ...

  9. Zabbix 3.0 配置企业微信报警(配置zabbix-web)

    一.添加报警媒体类型 Name:自定义 Type:选择script Scripts name:填写脚本名称 Script parameters:脚本参数 --corpid=XXX --corpsecr ...

  10. linux用户态和内核态理解

    1.特权级         Intel x86架构的cpu一共有0-4四个特权级,0级最高,3级最低,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查.硬件已经提供了一套特权级使用的相关机制 ...