0

0

JAVA Spring Data JPA中的动态查询代码详解

Y2J

Y2J

发布时间:2017-04-25 16:42:56

|

2843人浏览过

|

来源于php中文网

原创

spring data jpa大大的简化了我们持久层的开发,但是实际应用中,我们还是需要动态查询的。

比如,前端有多个条件,这些条件很多都是可选的,那么后端的SQL,就应该是可以定制的,在使用hibernate的时候,可以通过判断条件来拼接SQL(HQL),当然,Spring Data JPA在简化我们开发的同时,也是提供了支持的。

通过实现Criteria二实现的动态查询,需要我们的Repo接口继承JpaSpecificationExecutor接口,这是个泛型接口。

然后查询的时候,传入动态查询参数,分页参数等即可。

使用起来很简单,不过为了知其所以然,先介绍一下Criteria API。

立即学习Java免费学习笔记(深入)”;

Criteria API

如果编译器能够对查询执行语法正确性检查,那么对于 Java 对象而言该查询就是类型安全的。Java™Persistence API (JPA) 的 2.0 版本引入了 Criteria API,这个 API 首次将类型安全查询引入到 Java 应用程序中,并为在运行时动态地构造查询提供一种机制。本文介绍如何使用 Criteria API 和与之密切相关的 Metamodel API 编写动态的类型安全查询。

在使用Spring Data JPA的时候,只要我们的Repo层继承JpaSpecificationExecutor接口就可以使用Specification进行动态查询了,我们先看下JpaSpecificationExecutor接口:

public interface JpaSpecificationExecutor { 
 T findOne(Specification spec); 
 List findAll(Specification spec); 
 Page findAll(Specification spec, Pageable pageable); 
 List findAll(Specification spec, Sort sort); 
 long count(Specification spec); 
}

可以看到提供了5个方法,方法的参数和返回值已经很明显的表达了其意图。其中的参数,Pageable和Sort应该是比较简单的,分别是分页参数和排序参数,而重点就是Specification参数,先看下这个接口的定义:

public interface Specification { 
 Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb); 
}

其中就一个方法,返回的是动态查询的数据结构。


javax.persistence.criteria.Predicate toPredicate(javax.persistence.criteria.Root root,
javax.persistence.criteria.CriteriaQuery query,
javax.persistence.criteria.CriteriaBuilder cb);

这里使用的都是Java EE中的规范,具体实现本人采用的是Hibernate,当然也可以选择其他实现了JPA规范的数据持久层框架。
这里需要再次回过头看看Criteria API中的一些东西:

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

Cutout.Pro抠图
Cutout.Pro抠图

AI批量抠图去背景

下载

CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用

Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似

1:Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。

2:查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。

3:Criteria查询,可以有多个查询根。

4:AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法。CriteriaBuilder接口:用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合

其中支持的方法非常之强大,下面给出一个示例,大家可以参考一下,同样的,可以根据示例,自己可以写出更为复杂的查询:

Repo接口:

public interface DevHREmpConstrastDao 
 extends JpaRepository,JpaSpecificationExecutor

查询实例1:

/** 
 * 条件查询时动态组装条件 
 */ 
private Specification where( 
  final String corg,final String name,final String type,final String date,final String checker){ 
 return new Specification() { 
  @Override 
  public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { 
   List
 predicates = new ArrayList
(); 
   //机构 
   if(corg!=null&&!corg.equals("")){ 
    List orgIds = organizationDao.findByName("%"+corg+"%"); 
    if(orgIds.size()>0&&orgIds.size()<1000) 
     predicates.add(root.get("confirmOrgNo").in(orgIds));//confirmOrgNo 
   } 
   //名字 
   if(name!=null&&!name.equals("")){ 
    List userIds = userDao.findByName(name); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.get("hrUserName").in(userIds)); 
   } 
   //类型 
   if(type!=null&&!type.equals("")) 
    predicates.add(cb.equal(root.get("hrUpdateType"),type)); 
   //日期 
   if(date!=null&&!date.equals("")){ 
    //处理时间 
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
    Date startDate; 
    Date endDate; 
    try { 
     startDate = format.parse(date); 
    } catch (ParseException e) { 
     startDate = new Date(946656000000L);//2000 01 01 
    } 
    endDate = startDate; 
    Calendar calendar = Calendar.getInstance() ; 
    calendar.setTime(endDate); 
    calendar.add(Calendar.DATE, 1); 
    endDate = calendar.getTime(); 
    calendar = null; 
    predicates.add(cb.between(root.get("insDate"),startDate,endDate)); 
   } 
   //审核人 
   if(checker!=null&&!checker.equals("")){ 
    List userIds = userDao.findByName(checker); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.get("confirmUserId").in(userIds)); 
   } 
   return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
  } 
 }; 
}

查询实例2:

/** 
 * 条件查询时动态组装条件 
 */ 
 private Specification where( 
   final String corg,final String name,final String type,final String date,final String checker){ 
  return new Specification() { 
   @Override 
   public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { 
    List
 predicates = new ArrayList
(); 
    //机构 
    if(corg!=null&&!corg.equals("")){ 
     List orgIds = organizationDao.findByName("%"+corg+"%"); 
     if(orgIds.size()>0&&orgIds.size()<1000) 
      predicates.add(root.get("confirmOrgNo").in(orgIds));//confirmOrgNo 
    } 
    //名字 
    if(name!=null&&!name.equals("")){ 
     List userIds = userDao.findByName(name); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.get("hrUserName").in(userIds)); 
    } 
    //类型 
    if(type!=null&&!type.equals("")) 
     predicates.add(cb.equal(root.get("hrUpdateType"),type)); 
    //日期 
    if(date!=null&&!date.equals("")){ 
     //处理时间 
     SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
     Date startDate; 
     Date endDate; 
     try { 
      startDate = format.parse(date); 
     } catch (ParseException e) { 
      startDate = new Date(946656000000L);//2000 01 01 
     } 
     endDate = startDate; 
     Calendar calendar = Calendar.getInstance() ; 
     calendar.setTime(endDate); 
     calendar.add(Calendar.DATE, 1); 
     endDate = calendar.getTime(); 
     calendar = null; 
     predicates.add(cb.between(root.get("insDate"),startDate,endDate)); 
    } 
    //审核人 
    if(checker!=null&&!checker.equals("")){ 
     List userIds = userDao.findByName(checker); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.get("confirmUserId").in(userIds)); 
    } 
    return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
   } 
  }; 
 }

然后调用dao层方法传入where()方法返回的参数即可。

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

40

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

50

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

12

2026.01.31

漫画防走失登陆入口大全
漫画防走失登陆入口大全

2026最新漫画防走失登录入口合集,汇总多个稳定可用网址,助你畅享高清无广告漫画阅读体验。阅读专题下面的文章了解更多详细内容。

13

2026.01.31

php多线程怎么实现
php多线程怎么实现

PHP本身不支持原生多线程,但可通过扩展如pthreads、Swoole或结合多进程、协程等方式实现并发处理。阅读专题下面的文章了解更多详细内容。

1

2026.01.31

php如何运行环境
php如何运行环境

本合集详细介绍PHP运行环境的搭建与配置方法,涵盖Windows、Linux及Mac系统下的安装步骤、常见问题及解决方案。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php环境变量如何设置
php环境变量如何设置

本合集详细讲解PHP环境变量的设置方法,涵盖Windows、Linux及常见服务器环境配置技巧,助你快速掌握环境变量的正确配置。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php图片如何上传
php图片如何上传

本合集涵盖PHP图片上传的核心方法、安全处理及常见问题解决方案,适合初学者与进阶开发者。阅读专题下面的文章了解更多详细内容。

2

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Spring中文手册
Spring中文手册

共0课时 | 0人学习

马士兵spring视频教程
马士兵spring视频教程

共25课时 | 9.1万人学习

Pandas 教程
Pandas 教程

共15课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号