Spring Data JPA虽然大大的简化了持久层的开发,但是在实际开发中,很多地方都需要高级动态查询,在实现动态查询时我们需要用到Criteria API,主要是以下三个:

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

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

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

  

  在JPA中,标准查询是以元模型的概念为基础的.元模型是为具体持久化单元的受管实体定义的.这些实体可以是实体类,嵌入类或者映射的父类.提供受管实体元信息的类就是元模型类。使用元模型类最大的优势是凭借其实例化可以在编译时访问实体的持久属性.该特性使得criteria 查询更加类型安全。例如:Product实体类对应的元模型Product_:

package powerx.io.bean;

import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel; @Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Product.class)
public abstract class Product_ { public static volatile SingularAttribute<Product, Double> price;
public static volatile SingularAttribute<Product, String> name;
public static volatile SingularAttribute<Product, Integer> id; }

  这样的元模型不用手动创建,有多种构建方式,本人使用的IDE是STS,具体操作如下:选中项目——鼠标右键Properties进入配置界面——java compiler下Annotation Processing——勾选enable project specific settings——Annotation Processing下Factory path——add external JARs ——加入事先下载好的hibernate-jpamodelgen-5.2.10.Final.jar——apply后则会在项目根目录下生成.apt_generated包,包内含有对应的实体类元模型(看不到的同学需要把resource过滤去掉),还有其它的方式,可参考http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html/chapter-usage.html。

  使用criteria 查询简单Demo

@Resource
private EntityManager entityManager; public List<Product> findByConditions(String name, Double price) {
//创建CriteriaBuilder安全查询工厂
//CriteriaBuilder是一个工厂对象,安全查询的开始.用于构建JPA安全查询.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
//创建CriteriaQuery安全查询主语句
//CriteriaQuery对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。
CriteriaQuery<Product> query = criteriaBuilder.createQuery(Product.class);
//Root 定义查询的From子句中能出现的类型
Root<Product> ProductRoot = query.from(Product.class);
//Predicate 过滤条件 构建where字句可能的各种条件
//这里用List存放多种查询条件,实现动态查询
List<Predicate> predicatesList = new ArrayList<>();
//name模糊查询 ,like语句
if (name != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
ProductRoot.get(Product_.name), "%" + name + "%")));
}
// ProductPrice 小于等于 <= 语句
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
ProductRoot.get(Product_.price), price)));
} query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
TypedQuery<Product> typedQuery = entityManager.createQuery(query);
List<Product> resultList = typedQuery.getResultList();
return resultList;
}

  criteriaBuilder中各方法对应的语句:  

  equle : filed = value

  gt / greaterThan : filed > value

  lt / lessThan : filed < value

  ge / greaterThanOrEqualTo : filed >= value

  le / lessThanOrEqualTo: filed <= value

  notEqule : filed != value

  like : filed like value

  notLike : filed not like value

  

  如果每个动态查询的地方都这么写,那就感觉太麻烦了。那实际上,在使用Spring Data JPA的时候,只要我们的Repo层接口继承JpaSpecificationExecutor接口就可以使用Specification进行动态查询,在这里因为findAll(Specification<T> var1, Pageable var2)方法中参数 Specification<T> 是一个匿名内部类

那这里就可以直接用lambda表达式直接简化代码。

  持久层接口类:

package powerx.io;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import powerx.io.bean.Product; public interface ProductDao extends JpaRepository<Product, Integer>,JpaSpecificationExecutor<Product> { }

  service层:

@Autowired
private ProductDao productDao; public List<Product> findByConditions2(String name, Double price) {
return productDao.findAll((root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicatesList = new ArrayList<>();
if (name != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
root.get(Product_.name), "%" + name + "%")));
}
// itemPrice 小于等于 <= 语句
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
root.get(Product_.price), price)));
}
return criteriaBuilder.and(
predicatesList.toArray(new Predicate[predicatesList.size()]));
});
}

  控制器类:

package powerx.io;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; @RestController
public class ProductController { @Autowired
private ProductServiceImpl productServiceImpl; @GetMapping("/find")
public Object find(@RequestParam String name ,@RequestParam Double price) {
return productServiceImpl.findByConditions2(name, price);
}
}

  实体类:

package powerx.io.bean;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; @Entity
public class Product implements Serializable{ private static final long serialVersionUID = 5800591455207338888L; @Id
@GeneratedValue
private Integer id; private String name; private Double price; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Double getPrice() {
return price;
} public void setPrice(Double price) {
this.price = price;
} }

  使用springboot构建项目,pom.xml 和application.yml如下

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- 连接mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency> <!-- 整合jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
spring:
datasource:
url: jdbc:mysql://localhost:3306/springdatajpa
username: root
password: root
jpa:
show-sql: true
hibernate:
ddl-auto: update

  启动项目,会根据实体类自动创建对应的表,加入测试数据,访问http://localhost:8080/find?name=apple&price=88,结果如下:

  参考文章:https://www.jianshu.com/p/0939cec7e207

springboot整合spring data jpa 动态查询的更多相关文章

  1. springboot整合spring Data JPA

    今天敲代码,一连串的错误,我也是服气~果然,我们不是在出bug,就是在找bug的路上…… 今天完成的是springboot整合spring data JPA ,出了一连串的错,真是头大 java.sq ...

  2. springboot集成Spring Data JPA数据查询

    1.JPA介绍 JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.它的出现主要是为 ...

  3. spring data jpa 动态查询(工具类封装)

    利用JPA的Specification<T>接口和元模型就实现动态查询了.但是这样每一个需要动态查询的地方都需要写一个这样类似的findByConditions方法,小型项目还好,大型项目 ...

  4. Spring Data JPA动态查询(多条件and)

    entity: @Entity @Table(name = "data_illustration") public class Test { @Id @GenericGenerat ...

  5. spring-boot (三) spring data jpa

    学习文章来自:http://www.ityouknow.com/spring-boot.html spring data jpa介绍 首先了解JPA是什么? JPA(Java Persistence ...

  6. spring data jpa 分页查询

    https://www.cnblogs.com/hdwang/p/7843405.html spring data jpa 分页查询   法一(本地sql查询,注意表名啥的都用数据库中的名称,适用于特 ...

  7. Spring Boot 整合Spring Data JPA

    Spring Boot整合Spring Data JPA 1)加入依赖 <dependency> <groupId>org.springframework.boot</g ...

  8. Spring Boot从入门到精通(九)整合Spring Data JPA应用框架

    JPA是什么? JPA全称Java Persistence API,是Sun官方提出的Java持久化规范.是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. ...

  9. Spring Boot 入门系列(二十七)使用Spring Data JPA 自定义查询如此简单,完全不需要写SQL!

    前面讲了Spring Boot 整合Spring Boot JPA,实现JPA 的增.删.改.查的功能.JPA使用非常简单,只需继承JpaRepository ,无需任何数据访问层和sql语句即可实现 ...

随机推荐

  1. 检测远程主机上的某个端口是否开启——telnet命令

    要测试远程主机上的某个端口是否开启,无需使用太复杂的工作,windows下就自带了工具,那就是telnet.ping命令是不能检测端口,只能检测你和相应IP是否能连通. 1 安装telnet.win7 ...

  2. ARM汇编中一些重要伪指令

    IMPORT ,定义表示这是一个外部变量的标号,不是在本程序定义的 EXPORT ,表示本程序里面用到的变量提供给其他模块调用的. 以上两个在汇编和C语言混合编程的时候用到 ENDP    表示PRO ...

  3. 使用 JAVA 中的动态代理实现数据库连接池

    数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈.我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共 ...

  4. 第几天——第九届蓝桥杯C语言B组(省赛)第一题

    原创 标题:第几天 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数,不要填写任何多余内容. 这题是送分题,只需要注意一下2000年 ...

  5. 你不知道的Console

    1.凡人视角 打印字符串 代码: console.log("I am a 凡人"); 打印提示消息 代码: console.info("Yes, you arm a 凡人 ...

  6. ThinkJS 中的Logic层

    第一个为什么需要Logic层: 当在 Action 里处理用户的请求时,经常要先获取用户提交过来的数据,然后对其校验,如果校验没问题后才能进行后续的操作:当参数校验完成后,有时候还要进行权限判断等,这 ...

  7. config的配置文件

  8. C/C++学习的50个经典网站

    C/C++是最主要的编程语言.这里列出了50名优秀网站和网页清单,这些网站提供c/c++源代码.这份清单提供了源代码的链接以及它们的小说明.我已尽力包括最佳的C/C++源代码的网站.这不是一个完整的清 ...

  9. unigui不是单个网页相应的链接,而是整体Web Application,如何把webApp的子功能映射到微信公众号菜单?

    只需要用UniApplication.Parameters.Values[‘xxx’]读取url的参数然后调用就可以 例如:要打开公众号菜单的取样送检指南查询模块,在自定义菜单设定:http://ww ...

  10. 介绍自己以及github注册流程

    我叫何季生,来自网络工程141,学号是1413042027,我喜欢看一些动漫和游戏,对于编程并不是很厉害希望今年能够有所突破. github注册流程:在刚开始注册github时,我用的是qq浏览器,却 ...