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. 编写高质量代码改善C#程序的157个建议——建议147:重构多个相关属性为一个类

    建议147:重构多个相关属性为一个类 若存在多个相关属性,就应该考虑是否将其重构为一个类.查看如下类: class Person { public string Address { get; set; ...

  2. sqlplus 简单的几个查询语句

    sqlplus 是用来和oracle进行交互的工具,可以在电脑端使用,也可以在服务器使用 常用命令    show        显示SQL Plus中的信息 connect        先无条件断 ...

  3. javascript事件坐标

    clientX 鼠标在页面显示区域的坐标 screenX鼠标在显示屏幕上的坐标 layerX 鼠标相对于“触发事件的元素的层级关系中离该元素最近的,设置了position的父元素”的边界的位置,从bo ...

  4. 【Linux】Vim编辑器

    本文基于Debian 1.vim使用简介 1.1vim安装 使用apt安装vim即可: sudo apt-get install vim 1.2 vim编辑器的模式 vim编辑器分为命令模式和编辑模式 ...

  5. Partition--分区Demo

    --============================================================= --创建分区函数 --创建500分区,分区键按照1000依次递增 CRE ...

  6. (zxing.net)一维码Code 39的简介、实现与解码

    一.简介 一维码Code 39:由于编制简单.能够对任意长度的数据进行编码.支持设备广泛等特性而被广泛采用. Code 39码特点: 能够对任意长度的数据进行编码,其局限在于印刷品的长度和条码阅读器的 ...

  7. django media配置

    当我们需要向服务器发送图片或视频,需要对这些媒体文件进行保存时,需要指定保存在哪并将保存的路径添加到路由中. 1.设置settings.py MEDIA_URL = '/media/' MEDIA_R ...

  8. 8、insert、delete、update语句总结

    insert常用语句 > insert into tb1 (name,age) values('tom',33); > insert into tb1 (name,age) values( ...

  9. 基于DALN方案C/S架构运用

    今天闲来无事,看到笔记本的蓝牙设备想着:可不可以实现电脑端播放手机端的音频. 刚刚开始想着基于蓝牙,尝试多次无解(主要原因是没有找到支持此功能的软件) 最后:有朋友建议可以研究下DALN方案解决这个需 ...

  10. mysql查询语句常用字段操作函数

    一.concat()函数 1.功能:将多个字符串连接成一个字符串. 2.语法:concat(str1, str2,...) 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为nu ...