Spring Boot 学习研究笔记(十七) -Spring boot JPA的复杂查询

简介: Spring Boot 学习研究笔记(十七) -Spring boot JPA的复杂查询

Spring boot JPA的复杂查询

 

一、 JpaSpecificationExecutor 接口查询方式

1、JpaSpecificationExecutor接口

JPA 提供动态接口JpaSpecificationExecutor,利用类型检查的方式,利用Specification进行复杂的条件查询,比自己写 SQL 更加便捷和安全。

JpaSpecificationExecutor 源码

public interface JpaSpecificationExecutor<T> {
    /**
     * Returns a single entity matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    T findOne(Specification<T> spec);
    /**
     * Returns all entities matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    List<T> findAll(Specification<T> spec);
    /**
     * Returns a {@link Page} of entities matching the given {@link Specification}.
     * 
     * @param spec
     * @param pageable
     * @return
     */
    Page<T> findAll(Specification<T> spec, Pageable pageable);
    /**
     * Returns all entities matching the given {@link Specification} and {@link Sort}.
     * 
     * @param spec
     * @param sort
     * @return
     */
    List<T> findAll(Specification<T> spec, Sort sort);
    /**
     * Returns the number of instances that the given {@link Specification} will return.
     * 
     * @param spec the {@link Specification} to count instances for
     * @return the number of instances
     */
    long count(Specification<T> spec);
}

2、Specification 说明

Specification是我们传入进去的查询参数,是一个接口,并且只有一个方法。

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

3、toPredicate 函数参数说明:

  • Root: 是查询结果的一个实体对象,也就是查询结果返回的主要对象。

root = query.from(User.class);

  •  
  • CriteriaQuery:是JPA标准,主要是构建查询条件的,里面的方法都是各种查询方式:distinct、select、where、groupby、having、orderby这些方法。

// query = cb.createQuery(User.class);//

  •  
  • CriteriaBuilder:主要用来生成Predicate接口 。其中包含between、gt(大于)、lt(小于)、not(非)等等操作。

4、JpaSpecificationExecutor 内部查询原理

第一步,使用EntityManager 获得 CriteriaBuilder 查询工厂;

第二步,使用 CriteriaBuilder 获得查询类 CriteriaQuery;

第三步,组装查询条件数组 List<Predicate> ;

第四步,使用CriteriaQuery where 拼接 or 或and + 条件数组;

第五步,使用 EntityManager 进行查询;

 

重点说一下

JPA标准中Hibernate的两个实现方法:

org.hibernate.ejb.criteria.CriteriaBuilderImpl.and(Predicate...)

org.hibernate.ejb.criteria.CriteriaBuilderImpl.or(Predicate...)

这两个方法都有一个关键的接口: Predicate(javax.persistence.criteria.Predicate)

这个接口同为Expression的子接口,作为关联各种Predicate的核心操作接口:

and:是将各个条件作为and来拼接,进行查询。

or:是将各条件作为or来拼接,进行查询。

 

代码演示查询流程

@PersistenceContext
private EntityManager em;
@Override
public List<Even> list(Even even) {
    //查询工厂
    CriteriaBuilder cb = em.getCriteriaBuilder();
    //查询类
    CriteriaQuery<Even> query = cb.createQuery(Even.class);
    //查询条件
    List<Predicate> predicates = new LinkedList<>();
    //查询条件设置
    predicates.add(cb.equal("id", even.getId()));
    predicates.add(cb.like("eventTitle", even.getEventTitle()));
    //拼接where查询
    query.where(cb.or(predicates.toArray(new Predicate[predicates.size()])));
    //用JPA 2.0的TypedQuery进行查询
    TypedQuery<Even> typedQuery = em.createQuery(query);
    return typedQuery.getResultList();
}

 

5 、使用步骤:

(1)、对应的Repository需要实现JpaSpecificationExecutor接口

public interface UserRepository extends JpaRepository<User, Long> ,

           JpaSpecificationExecutor<User>{

 

(2)、在业务层编写你具体的复杂查询语句

新建一个条件构造器,重写oPredicate方法:

@Override
    public Page<泛型> findRecordList(int couponDetailId, int pageNum, int pageSize, String startTime, String endTime) {
        try {
        //排序规则和分页
            Sort sort = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
            PageRequest pageRequest = new PageRequest(pageNum - 1, pageSize, sort);
            Specification specification = new Specification() {
                @Override
                public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            //增加筛选条件
                    Predicate predicate = cb.conjunction();
                    predicate.getExpressions().add(cb.equal(root.get("cardId"), couponDetailId));
            //起始日期
                    if (startTime != null && !startTime.trim().equals("")) {
                        predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("createTime").as(String.class), startTime));
                    }
            //结束日期
                    if (endTime != null && !endTime.trim().equals("")) {
                        predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("createTime").as(String.class), endTime));
                    }
                    return predicate;
                }
            };
            Page all = discountCouponRecordDao.findAll(specification, pageRequest);
  return all;
}

 

二、自定义SQL

JPA同样允许自己写SQL操作记录。

实例:

接口:

@Query(value = "select * from order_info where user_name = ?1 and user_address = ?2", nativeQuery = true)

List<Order> selectByNameAndAddress(String name, String address);


@Modifying

@Transactional

@Query(value = "update order_info set user_address = ?1 where order_id = ?2", nativeQuery = true)

void updateAddressByOrderId(String address, Integer orderId);

注意: 1). 自定义SQL可以随便命名方法名

2).需要用@Query注解,如果是更新删除操作还需要有 @Modifying@Transactional 注解

3). SQL里的?表示的占位符,编译和执行的时候,取值是取接口的入参,?后的数字是第几个参数,从0开始


相关文章
|
4月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
4月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
4月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
561 2
|
5月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
4535 2
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
705 0
|
4月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
995 2
|
4月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
470 3
|
7月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
687 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
7月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1178 0
|
8月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
952 0