百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

JPA的好搭档 - QueryDSL(jpa的优势)

liuian 2025-06-28 15:16 34 浏览

今天给大家介绍一个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 的高级用法。

相关推荐

isofix接口(isofix接口怎么拆卸)

isofix接口上有isofix的字样,它的图标是一个类似人坐在座椅上。在汽车座椅靠垫与坐垫之间的连接处有2个接口,那就是isofix接口,是一种硬连接方式,为了防止撞击时发生座椅翻转,一些座椅在IS...

无线路由器怎么设置不让别人连接

要设置无线路由器不让别人连接,可以采取以下措施:1.配置路由器密码:在路由器设置中,可以设置密码,限制只有授權的人才能连接到网络。2.配置防火墙:可以安装防火墙软件,如OpenDNS,限制...

fast迅捷路由器(fast迅捷路由器配置上网教程)

http://www.fastcom.com.cn/上面这个就迅捷官网的网址老版本的迅捷路由器默认登录地址为“192.168.1.1”,新版本的迅捷路由器默认登录地址为“falogin.cn”。02...

手机天梯图2025最新版(手机天梯图cpu2020快科技)

一般情况下而言,手机处理器的性能越强,功耗也就越高。有网友制作了一张手机处理器功耗排名图,高通骁龙888位8.34W,是榜单中功耗第二的处理器。而海思麒麟9000则位列第三,功耗为8.3W。一般情况下...

pe系统下载官网手机版(pe系统之家)

打开手机应用商店,选择windowspe,下载安装PE系统是一种维护用的系统,本身是很简陋的,什么常用功能都没有,后经一些爱好都修改、完善,现在成为可当临时系统用的精简系统。但PE系统当前种类很多,...

云骑士装机大师怎么激活win7

回答如下:要激活Windows7操作系统,您可以按照以下步骤进行操作:1.确保您的计算机已连接到互联网。2.打开“开始”菜单,点击“计算机”右键,选择“属性”。3.在系统属性窗口中,向下滚动到...

vmware workstation使用教程

VMwareWorkstation15是一款虚拟机软件,可以在主机上模拟多个虚拟计算机环境。以下是使用VMwareWorkstation15的基本步骤:1.下载和安装软件:从VMware官方...

windows7旗舰版64位多少钱(windows7旗舰版64位多少钱合适)

这两个都是64位的,唯一区别是后者集成SP1。win7旗舰版64位玉米系统比较稳定,不但稳定,运行速度也很快!WIN764位系统需要的电脑配置。最低配置CPU:1GHz32位或2G...

电脑黑屏了怎么重装系统(电脑黑屏怎么重装系统win10)

我觉着吧,题主的判断可能是不正确的黑屏开不了机指的是开机后显示屏无任何信号接入首先从电源出发,电源的cpu供电,主板供电,显卡供电,硬盘供电,每一项都要确保接触完整再到主板,主板上呢,cpu散热必须接...

三星官网正品查询(三星全新正品查询网站)

三星服务中心地址:http://support-cn.samsung.com/support/ServiceLocations.asp国家工信部电信设备进网管理网站查询移动设备真伪方式:方法一:网站查...

显示windows许可证即将过期

电脑提示Windows许可证即将到期,可以采取以下措施:检查许可证状态:首先需要确认许可证是否真的即将过期。可以在Windows设置中查看许可证状态,或者运行命令“slmgr/xpr”来检查许可证到...

u盘看不到第二个分区(u盘不显示第二个分区)

u盘分区后不显示出来原因一般为以下三种:第一种情况:对于windows系统是只能识别U盘分区的。第二种情况:关于U盘的diskgenius分区是只能看到一个分区的第三种情况:这个U盘分区已经被隐藏了,...

小马激活重启电脑开不了机(小马激活重启后蓝屏怎么办)

1.无法激活2.小马激活工具可能无法激活的原因有很多,可能是因为软件本身存在bug或者与操作系统不兼容,也可能是因为网络连接问题或者输入的激活码有误。此外,小马激活工具可能需要特定的硬件或软件环境...

windows7 破解版(windows 7旗舰版破解密码)

步骤/方法按Windows徽标键+R(运行窗口),打开cmd运行窗口。输入slmgr.vbs-xpr后回车。这时会弹出一个窗口显示Win7的激活状态。Windows7旗舰版属于微软公司开发的...

专业数据恢复(专业数据恢复需要什么设备)

1、移动硬盘损坏以后,电脑无法识别到硬盘信息,那么整个硬盘数据将全部丢失。2、如果能够换一台电脑识别到,即使打不开,只要能够格式化,就有希望回复数据。可以尝试制作U盘系统盘的方法,打开u盘系统盘制作程...