JPA的好搭档 - QueryDSL

  发布时间:2025-11-04 10:49:44   作者:玩站小弟   我要评论
​0. 前言相对于 MyBatis ,本人更喜欢 Spring Data JPA ,因为它更符合面向对象的思想,然而 JPA 对复杂的查询支持较弱,常见的有两种方式:一种方式是Repository继承 。
​0. 前言

相对于 MyBatis ,的档本人更喜欢 Spring Data JPA ,好搭因为它更符合面向对象的的档思想,然而 JPA 对复杂的好搭查询支持较弱,常见的的档有两种方式:

一种方式是Repository继承JpaSpecificationExecutor接口,优点是好搭支持复杂查询、编译期可以规避一些语法错误,的档缺点是好搭语法晦涩难懂,学习成本太高。的档

JPA的好搭档 - QueryDSL

还有一种方式就是好搭直接写 SQL ,可以通过JdbcTemplate或者@Query注解的的档方式查询,优点是好搭简单,缺点嘛...先看段代码:

复制@Query(value="select bs.* from " + "(select t.baseid,的档t.basesn,t.basecreatorfullname,t.basestatus,t.basesummary,北京 faultprovince, 北京 faultcity, " + "replace(t.INC_ResponseLevel,响应,) inc_responselevel,t.inc_happentime,t.basecreatedate,t.inc_equipmentmanufacturer, " + "t.inc_ne_name,t.inc_alarm_id,t.site_alerttype,t.alarmlevel,t.inc_alarm_desc,t.baseacceptouttime,t.basedealouttime, " + "decode(t.flagPretreatment,null,否,未预处理,否,是) flagpretreatment,decode(t.flagPretreatment,null,否,未预处理,否,是) flagpretreatment2, " + "decode(nvl(t.isImportantIncident, 0),1,是,否) isimportantincident, decode(nvl(t.INC_IsEffectOP, 0),1,是,否) inc_iseffectop, " + "t.operationdeal, t.t0_deal,t.faultdescription,t.dealguomodo,t.inc_alarm_cleartime,t.clearinctime, " + "t.renewtime,t.baseclosedate,nvl2(t.checkdealresult,是,否) checkdealresult,g.jtitem1,g.jtitem2,g.jtitem3,t.reasontype " + "from T_DEMO t, T_DEMO_MAP g " + "where t.Sheet_type = 传输网络故障处理工单 and t.basestatus = 已归档 " + "and t.baseCloseDate >= :beginTime and t.baseCloseDate < :endTime " + "and (t.Withdraw_Desc = g.withdraw_desc or t.alarmname = g.alarmname) " + "union all " + "select t.baseid,t.basesn,t.basecreatorfullname,t.basestatus,t.basesummary,北京 faultprovince, 北京 faultcity, " + "replace(t.INC_ResponseLevel,响应,) inc_responselevel,t.inc_happentime,t.basecreatedate,t.inc_equipmentmanufacturer, " + "t.inc_ne_name,t.inc_alarm_id,t.site_alerttype,t.alarmlevel,t.inc_alarm_desc,t.baseacceptouttime,t.basedealouttime, " + "decode(t.flagPretreatment,null,否,未预处理,否,是源码下载) flagpretreatment,decode(t.flagPretreatment,null,否,未预处理,否,是) flagpretreatment2, " + "decode(nvl(t.isImportantIncident, 0),1,是,否) isimportantincident, decode(nvl(t.INC_IsEffectOP, 0),1,是,否) inc_iseffectop, " + "t.operationdeal,t.t0_deal,t.faultdescription,t.dealguomodo,t.inc_alarm_cleartime,t.clearinctime, " + "t.renewtime,t.baseclosedate,nvl2(t.checkdealresult,是,否) checkdealresult,w.jtitem1,w.jtitem2,w.jtitem3,t.reasontype " + "from WF_BMCC_EOMS_ITDealFault t, (select distinct c.value,c.jtitem1,c.jtitem2,c.jtitem3 from WF_Config_EL_00_NetType c) w " + "where (t.Sheet_type = test0 or t.Sheet_type = test1 or t.Sheet_type = test2 " + "or t.Sheet_type = test3 or t.Sheet_type = test4) and t.basestatus = 已归档 " + "and t.baseCloseDate >= :beginTime and t.baseCloseDate < :endTime " + "and t.faultclass = w.value "+ " ) bs " + "where not exists (select dp.processbaseid from T_DEAL dp,T_GROUPS dg where dp.ProcessBaseSchema = " + "DEALFAULT and dp.processbaseid = bs.baseid and dp.groupid = dg.groupid) ", nativeQuery=true) List<DemoEntity> findOne(@Param("beginTime") long beginTime, @Param("endTime") long endTime);1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.

看着想吐,就是好搭直接写SQL的缺点。

下面隆重介绍 JPA 的的档最佳搭档:QueryDSL。它的语法跟SQL一样简单,且代码清晰,具有代码提示、编译期错误检查等优势。同时,在架构的层次上实现了读写分离:JPA负责增删改、QueryDSL负责查询。

1. QueryDsl介绍

QueryDSL 是一个通用的查询框架,专注于通过 Java API 构建类型安全的SQL查询。

QueryDSL 可以通过一组通用的查询 API 为用户构建出适合不同类型ORM框架或者是 SQL 的查询语句,也就是说 QueryDSL 是基于各种 ORM 框架以及 SQL 之上的一个通用的服务器托管查询框架。

借助 QueryDSL 可以在任何支持的 ORM 框架或者 SQL 平台上以一种通用的API方式来构建查询。目前 QueryDSL 支持的平台包括 JPA、JDO、SQL、Mongodb 等等。

2. 引入QueryDSL

本文以gradle构建为例,前提是已引入 Spring Data Jpa ,且JPA可正常使用。

复制implementation com.querydsl:querydsl-jpaannotationProcessor com.querydsl:querydsl-apt:5.0.0:jpaannotationProcessor jakarta.persistence:jakarta.persistence-api1.2.3.

引入JPAQueryFactory

复制@Service

public class DemoQueryDSL {

@Autowired

private JPAQueryFactory queryFactory;}1.2.3.4.5. 3. 创建JPA Entity

我们分别创建两个示例实体类:职员表、部门表。

复制/** * 职员表 */

@Data

@Entity

@Table(name = "T_EMP")public class Emp {

@Id

private String id;//

ID

@Column

private String name;//

姓名

@Column

private Integer age;//

年龄

@Column

private String sex;//

性别

@Column

private String depId;//

部门ID

}/** * 部门表 */

@Data

@Entity

@Table(name = "T_DEP")public class Dep {

@Id

private String id;//

ID

@Column

private String depName;//

部门名称

}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.

编译后,QueryDSL 会帮助我们会自动生成两个Q类:QEmp、QDep ,我们之后进行的所有查询都是围绕这些Q类来进行的。

4. 简单查询

QueryDSL提供了一种类似于SQL的面向对象写法,并且是类型安全的,搭配上IDEA的语句提示功能,写起SQL来非常舒服。

请欣赏下面的例子:

复制public void simpleSql(){ QEmp emp = QEmp.emp;//

员工表

/** * 简单条件查询、排序,网站模板相当于sql: * select * from T_EMP * where name like 张% and age > 25 * order by age desc; */ List<Emp> empList = queryFactory.select(emp) .where(emp.name.startsWith("张").and(emp.age.gt(25))) .orderBy(emp.age.desc()) .fetch(); /** * 分组查询,相当于sql: * select e.dep_id, max(e.age) from T_EMP e * grouping by e.depId; */ List<Tuple> list = queryFactory.select(emp.depId, emp.age.max()) .groupBy(emp.depId) .fetch(); /** * 分页查询,相当于sql: * select * from T_EMP e * where e.dep_id=123 * limit 20 10; */ List<Emp> pageList = queryFactory.select(emp) .where(emp.depId.eq("123")) .offset(20) .limit(10) .fetch();}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34. 5. 复杂查询

QueryDSL对于复杂查询的支持也是相当优秀的,比如多表关联、动态条件查询等。

复制public void complexSql(){ QEmp emp = QEmp.emp;//

员工表

QDep dep = QDep.dep;//

部门表

/** * 关联查询,相当于sql: * select e.* from T_EMP e * left join T_DEP d on e.dep_id = d.id * where d.dep_name = 财务部 */ List<Emp> empList = queryFactory.select(emp) .from(emp) .leftJoin(dep).on(emp.depId.eq(dep.id)) .where(dep.depName.eq("财务部")) .fetch(); /** * 嵌套查询,相当于sql: * select e.* from T_EMP e * where e.dep_id = ( * select id form T_DEP where dep_name = 财务部 * ) */ List<Emp> empList1 = queryFactory.select(emp) .from(emp) .where(emp.depId.eq( queryFactory.select(dep.id).from(dep) .where(dep.depName.eq("财务部")) )) .fetch(); /** * 动态条件、别名、获取不同结果: */ BooleanBuilder condition = new BooleanBuilder(); condition.and(emp.age.goe(25)); if (true) {//

动态条件

condition.and(emp.sex.eq("男"));} queryFactory.select(emp.name.as("fullname")) .where(condition) .fetch();//

查找多个结果,返回集合

//.fetchOne();//

查询只返回一个结果,如果返回多个则抛异常

//.fetchFirst();//

返回多个结果时,只取第一个

}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46. 小结

以上就是 QueryDSL 的简单应用,用写SQL的方法来写代码,是不是很舒服呢!文中的例子仅仅浅尝辄止,希望大家可以实际应用一下,后续我也会更深入的讲解一些 QueryDSL 的高级用法。

  • Tag:

相关文章

  • 学习如何以dpi大小设置教程(让你的设计更加精确和专业化)

    摘要:随着科技的不断进步和设计行业的发展,人们对于图像和设计的要求也越来越高。而dpidotsperinch,每英寸点数)的大小设置对于图像的质量和打印效果起着关键性的作用。本文将为大...
    2025-11-04
  • 智慧城市的数字解决方案

    通过物联网(IoT)建设的智慧城市可以解决居民面临的重大挑战——公共安全、交通、空气质量、照明、公共交通等等。想象一下,一个城市拥有记录交通模式的传感器。这些数据被分析,然后交通信号可以根据交通需求进
    2025-11-04
  • 智慧城市会是可持续发展城市的代名词吗?

    到2050年,预计世界上85%的人口将居住在城市。这意味着在未来几年,城市将不得不面临与能源供应、二氧化碳排放、交通规划、货物和材料供应等因人口过剩而产生的新问题。解决方案的一部分是在所涉及的资产之间
    2025-11-04
  • 物联网如何彻底改变可持续发展

    在我们追求一个更可持续发展的世界的过程中,技术进步发挥了至关重要的作用。物联网(IoT)就是重塑可持续发展格局的突破性创新之一。物联网和可持续发展的结合带来了巨大的希望,为应对环境挑战提供了创新的解决
    2025-11-04
  • 雷神电脑轻松使用教程(让你掌握雷神电脑的使用技巧)

    摘要:雷神电脑作为一款性能强大的笔记本电脑,备受用户喜爱。然而,对于新手来说,可能会面临一些使用上的困惑。本篇文章将为你介绍雷神电脑的一些基本功能和使用技巧,帮助你轻松上手。快速...
    2025-11-04
  • 物联网是人工智能进化的支点

    人工智能(AI)和物联网(IoT)是我们这个时代最具颠覆性的两种技术,它们能够感知、检测、倾听、预测并最终帮助人们。它们共同形成强大的协同效应,可以实现行业转型、提高效率,并为企业和消费者创造新的价值
    2025-11-04

最新评论