JPA的好搭档 - QueryDSL

网友投稿 661 2023-04-22

JPA的好搭档 - QueryDSL

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 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可正常使用。

引入JPAQueryFactory

@Servicepublic 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 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 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 pageList = queryFactory.select(emp) .where(emp.depId.eq("123")) .offset(20) .limit(10) .fetch();}

5. 复杂查询

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

小结

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小工具:助你上手分布式数据库
下一篇:数据库国产化替代之后,补坑之路从未止步……
相关文章