网站首页 > 博客文章 正文
今天给大家介绍一个JPA的好搭档:QueryDSL。
0. 前言
相对于 MyBatis ,本人更喜欢 Spring Data JPA ,因为它更符合面向对象的思想,然而 JPA 对复杂的查询支持较弱,常见的有两种方式:
一种方式是Repository继承JpaSpecificationExecutor接口,优点是支持复杂查询、编译期可以规避一些语法错误,缺点是语法晦涩难懂,学习成本太高。
还有一种方式就是直接写 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);
看着想吐,就是直接写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-jpa'
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jpa'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
引入JPAQueryFactory
@Service
public class DemoQueryDSL {
@Autowired
private JPAQueryFactory queryFactory;
}
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;//部门名称
}
编译后,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();
}
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();//返回多个结果时,只取第一个
}
小结
以上就是 QueryDSL 的简单应用,用写SQL的方法来写代码,是不是很舒服呢!文中的例子仅仅浅尝辄止,希望大家可以实际应用一下,后续我也会更深入的讲解一些 QueryDSL 的高级用法。
猜你喜欢
- 2024-10-24 持久层框架JPA与Mybatis该如何选型
- 2024-10-24 hibatis--mybatis,自动生成SQL, 通用Mapper, 通用Dao
- 2024-10-24 Elasticsearch 6.0.0官方参考指南翻译
- 2024-10-24 推荐一个高效美观易用的服务器运维工具
- 2024-10-24 Java 操作之RestHighLevelClient查询详解
- 2024-10-24 如何在 Elasticsearch 上应用机器学习排序插件
- 2024-10-24 「开源资讯」Apache Solr 8.6.0 发布,Java 全文搜索服务器
- 2024-10-24 最轻量级的Kubernetes云原生日志框架Loki
- 2024-10-24 ElasticSearch学习系列 - (3) Python操作es
- 2024-10-24 全功能orm工具sorms 1.0.10 发布,合使用Spring,Spring boot用户
你 发表评论:
欢迎- 05-30springboot 集成redisson 以及分布式锁的使用
- 05-30去哪儿技术面:10亿数据如何最快速插入MySQL?
- 05-30redis介绍
- 05-30redission YYDS
- 05-30手把手教你springboot集成mybatis
- 05-30mybatis根据表逆向自动化生成代码:自动生成实体类、mapper文件
- 05-30越来越大的微信小程序
- 05-30SpringBoot之数据访问——访问SQL数据库!
- 422℃用AI Agent治理微服务的复杂性问题|QCon
- 420℃手把手教程「JavaWeb」优雅的SpringMvc+Mybatis整合之路
- 401℃初次使用IntelliJ IDEA新建Maven项目
- 399℃Maven技术方案最全手册(mavena)
- 394℃IntelliJ IDEA 2018版本和2022版本创建 Maven 项目对比
- 389℃InfoQ 2024 年趋势报告:架构篇(infoq+2024+年趋势报告:架构篇分析)
- 389℃从头搭建 IntelliJ IDEA 环境(intellij idea建包)
- 384℃IT全明星|IntelliJ IDEA学习笔记(四、idea中怎么创建maven项目)
- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)