Spring Data JPA实现动态查询的两种方法

 更新时间:2017年04月01日 11:21:13   作者:lulll  
本篇文章主要介绍了Spring Data JPA实现动态查询的两种方法,具有一定的参考价值,有兴趣的可以了解一下。

前言

一般在写业务接口的过程中,很有可能需要实现可以动态组合各种查询条件的接口。如果我们根据一种查询条件组合一个方法的做法来写,那么将会有大量方法存在,繁琐,维护起来相当困难。想要实现动态查询,其实就是要实现拼接SQL语句。无论实现如何复杂,基本都是包括select的字段,from或者join的表,where或者having的条件。在Spring Data JPA有两种方法可以实现查询条件的动态查询,两种方法都用到了Criteria API。

Criteria API

这套API可用于构建对数据库的查询。

类型安全。通过定义元数据模型,在程序编译阶段就可以对类型进行检查,不像SQL需要与Mysql进行交互后才能发现类型问题。

如下即为元数据模型。创建一个元模型类,类名最后一个字符为下划线,内部的成员变量与UserInfo.class这个实体类的属性值相对应。

@StaticMetamodel(UserInfo.class)
public class UserInfo_ {
  public static volatile SingularAttribute<UserInfo, Integer> userId;
  public static volatile SingularAttribute<UserInfo, String> name;
  public static volatile SingularAttribute<UserInfo, Integer> age;
  public static volatile SingularAttribute<UserInfo, Long> high;
}

可移植。API并不依赖具体的数据库,可以根据数据库类型的不同生成对应数据库类型的SQL,所以其为可移植的。

面向对象。Criteria API是使用的是各种类和对象如CriteriaQuery、Predicate等构建查询,是面向对象的。而如果直接书写SQL则相对于面向的是字符串。

第一种:通过JPA的Criteria API实现

  1. EntityManager获取CriteriaBuilder
  2. CriteriaBuilder创建CriteriaQuery
  3. CriteriaQuery指定要查询的表,得到Root<UserInfo>,Root代表要查询的表
  4. CriteriaBuilder创建条件Predicate,Predicate相对于SQL的where条件,多个Predicate可以进行与、或操作。
  5. 通过EntityManager创建TypedQuery
  6. TypedQuery执行查询,返回结果
public class UserInfoExtendDao {

 @PersistenceContext(unitName = "springJpa")
 EntityManager em;

 public List<UserInfo> getUserInfo(String name,int age,int high) {
   CriteriaBuilder cb = em.getCriteriaBuilder();
   CriteriaQuery<UserInfo> query = cb.createQuery(UserInfo.class);

   //from
   Root<UserInfo> root = query.from(UserInfo.class);

   //where
   Predicate p1 = null;
   if(name!=null) {
     Predicate p2 = cb.equal(root.get(UserInfo_.name),name);
     if(p1 != null) {
       p1 = cb.and(p1,p2);
     } else {
       p1 = p2;
     }
   }

   if(age!=0) {
     Predicate p2 = cb.equal(root.get(UserInfo_.age), age);
     if(p1 != null) {
       p1 = cb.and(p1,p2);
     } else {
       p1 = p2;
     }
   }

   if(high!=0) {
     Predicate p2 = cb.equal(root.get(UserInfo_.high), high);
     if(p1 != null) {
       p1 = cb.and(p1,p2);
     } else {
       p1 = p2;
     }
   }
   query.where(p1);

   List<UserInfo> userInfos = em.createQuery(query).getResultList();
   return userInfos;
 }
}

第二种:DAO层接口实现JpaSpecificationExecutor<T>接口

JpaSpecificationExecutor如下,方法参数Specification接口有一个方法toPredicate,返回值正好是Criteria API中的Predicate,而Predicate相对于SQL的where条件。与上一个方法相比,这种写法不需要指定查询的表是哪一张,也不需要自己通过Criteria API实现排序和分页,只需要通过新建Pageable、Sort对象并传参给findAll方法即可,简便一些。

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

UserInfoDao实现JpaSpecificationExecutor

public interface UserInfoDao 
  extends PagingAndSortingRepository<UserInfo, String>, JpaSpecificationExecutor<UserInfo> {}

实现Specification

public static Specification<UserInfo> getSpec(final String name,final int age,final int high) {
   return new Specification<UserInfo>() {
     @Override
     public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
       Predicate p1 = null;
       if(name!=null) {
         Predicate p2 = cb.equal(root.get(UserInfo_.name),name);
         if(p1 != null) {
           p1 = cb.and(p1,p2);
         } else {
           p1 = p2;
         }
       }

       if(age!=0) {
         Predicate p2 = cb.equal(root.get(UserInfo_.age), age);
         if(p1 != null) {
           p1 = cb.and(p1,p2);
         } else {
           p1 = p2;
         }
       }

       if(high!=0) {
         Predicate p2 = cb.equal(root.get(UserInfo_.high), high);
         if(p1 != null) {
           p1 = cb.and(p1,p2);
         } else {
           p1 = p2;
         }
       }

       return p1;
     }
   };
 }

项目代码:springdatajpademo_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • springboot中如何替换class文件

    springboot中如何替换class文件

    这篇文章主要介绍了springboot中如何替换class文件,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 详解Spring 中如何控制2个bean中的初始化顺序

    详解Spring 中如何控制2个bean中的初始化顺序

    本篇文章主要介绍了Spring 中如何控制2个bean中的初始化顺序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • SpringBoot增量/瘦身部署jar包的方式

    SpringBoot增量/瘦身部署jar包的方式

    SpringBoot 项目的部署一般采用全量jar 包方式部署相关项目,如果我们对相关的Contrller层进行相关业务调整就需要重新编译全量jar 包太麻烦了,所以本文给大家介绍了使用SpringBoot 的增量/瘦身部署方式,需要的朋友可以参考下
    2024-01-01
  • Spring Validation方法实现原理分析

    Spring Validation方法实现原理分析

    这篇文章主要介绍了Spring Validation实现原理分析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Java堆&优先级队列示例讲解(下)

    Java堆&优先级队列示例讲解(下)

    这篇文章主要通过示例详细为大家介绍Java中的堆以及优先级队列,文中的示例代码讲解详细,对我们了解java有一定帮助,需要的可以参考一下
    2022-03-03
  • 浅谈SpringCloud之zuul源码解析

    浅谈SpringCloud之zuul源码解析

    这篇文章主要介绍了浅谈SpringCloud之zuul源码解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • 如何基于sqlite实现kafka延时消息详解

    如何基于sqlite实现kafka延时消息详解

    这篇文章主要给大家介绍了关于如何基于sqlite实现kafka延时消息的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • SpringBoot整合JDBC的实现

    SpringBoot整合JDBC的实现

    这篇文章主要介绍了SpringBoot整合JDBC的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java super和this的对比及使用

    Java super和this的对比及使用

    这篇文章主要介绍了Java super和this的对比及使用的相关资料,java中this与super会经常在使用的时候混淆,需要的朋友可以参考下
    2017-08-08
  • 使用jenkins部署springboot项目的方法步骤

    使用jenkins部署springboot项目的方法步骤

    这篇文章主要介绍了使用jenkins部署springboot项目的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04

最新评论