JPA在不写sql的情况下如何实现模糊查询

 更新时间:2024年11月20日 15:14:22   作者:武梓龙_Wzill  
文章介绍了在项目中实现模糊查询的几种方法,包括使用JPA的API、JPQL、QueryByExample和@Query注解,通过实现Specification接口和定义接口继承JpaRepository,可以方便地进行单字段和多字段的模糊查询,文章还提到了BINARY函数的使用以及查询结果的返回

背景介绍

在我们的项目中很多的业务都会设计模糊查询,例如按照姓氏去获取人员的信息,按照手机号的前三位去获取人员的信息等。

我们除了正常的手写模糊查询的sql语句去获取信息之外,还可以使用JPA自带的API来实现任意字段的模糊查询。

JPA已经给我们封装好了。当我们对模糊查询非常熟悉了之后直接拿来时候即可。

概念说明

单字段模糊匹配

  • 说明:在一个字段中无论关键字出现在什么位置上,只要有关键词即可。
  • 场景:获取手机号开头为187的学生
  • 应用:
SELECT*FROM table_name WHERE BINARY column_name LIKE'%keyword%';

多字段模糊匹配:

  • 说明:在多个字段中无论关键字出现在什么位置上,只要每个字段有每个字段指定的关键词即可。
  • 场景:获取手机号开头为187并且姓氏为武的学生
  • 应用:
SELECT*FROM table_name WHERE BINARY column1_name LIKE'%keyword1%'AND column2_name LIKE'%keyword2%';

注:

  • BINARY函数是开启大小写敏感的函数,底层逻辑是通过Ascii码的方式比较的。
  • 因为数据库默认是对大小写不敏感的,也就是我们在查询名称为wzl数据的时候,也会把名称为Wzl的数据也查询出来。

实现过程

代码实现

1.写一个实体类去实现Specification接口,重写toPredicate方法

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.tfjybj.dao.UserDao;
import com.tfjybj.utils.SnowflakeIdWorker;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @BelongsProject: incentive
 * @BelongsPackage: com.tfjybj.service
 * @Author: Wuzilong
 * @Description: 描述什么人干什么事儿
 * @CreateTime: 2023-08-28 14:48
 * @Version: 1.0
 */
@Table
@Entity
@Service
@Data
public class User implements Specification<User> {

    @Id
    @JsonSerialize(using = com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class)
    private Long id;

    private String account;

    private  String password;

    private String phone;

    private Date createTime;

    private Date updateTime;

    private Integer isDelete;

    @Resource
    @Transient
    private UserDao userDao;

    @Override
    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List<String> nonNullFields = new ArrayList<>();
        Field[] declaredFields = this.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            try {
                Object value = field.get(this);
                if (value != null) {
                    nonNullFields.add(field.getName());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        Predicate[] predicates = new Predicate[nonNullFields.size()+1];

        for (int i = 0; i < nonNullFields.size(); i++) {
            try {
                predicates[i] = criteriaBuilder.like(root.get(nonNullFields.get(i)), "%" + this.getClass().getDeclaredField(nonNullFields.get(i)).get(this) + "%");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 添加额外的条件,排除isdelete=1的数据
        predicates[nonNullFields.size()] = criteriaBuilder.notEqual(root.get("isDelete"), 1);

        return criteriaBuilder.and(predicates);
    }
}

本文中实现的是and方式的模糊查询,也可是使用or的方式进行模糊查询,也就是多个字段中都包含一个关键字。

2.定义一个接口去继承JpaRepository接口,并指定返回的类型和参数类型

@Entity
import com.tfjybj.service.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @BelongsProject: incentive
 * @BelongsPackage: com.tfjybj.dao
 * @Author: Wuzilong
 * @Description: 描述什么人干什么事儿
 * @CreateTime: 2023-08-28 14:48
 * @Version: 1.0
 */
@Repository
public interface UserDao extends JpaRepository<User, Long> {

    List<User> findAll(Specification<User> userInfo);
}

3.在业务类中调用声明的接口

@Entity
    public List<User> selectToFuzzy(User userInfo){
        List<User> userInfoList = userDao.findAll(userInfo);
        return userInfoList;
    }

4.在Controller中直接调用业务类中的方法即可

    @RequestMapping(value="selectToFuzzy",method= RequestMethod.POST)
    //模糊查询用户的信息
    public List<User> selectToFuzzy(@RequestBody User userInfo){
        List<User> users = user.selectToFuzzy(userInfo);
        return users;
    }

执行结果

可以看到我们的入参都是对应字段值的一部分内容,phone字段传入的是187它会把phone字段中包含187的所有数据都返回 回来。

同样两个字段一起模糊查询也是一样。

其他方式

1.使用JPQL进行模糊查询

使用LIKE关键字结合通配符(%)进行模糊匹配。

例如:

SELECT e FROM Employee e WHERE e.name LIKE '%John%'

2.使用Spring Data JPA的Query By Example进行模糊查询

创建一个实体对象作为查询条件,设置需要模糊匹配的属性值。

例如:

ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("name", match -> match.contains()); Example<Employee> example = Example.of(employee, matcher);

3.使用Spring Data JPA的@Query注解进行模糊查询

在Repository接口中使用@Query注解定义自定义的查询方法。

在查询方法中使用%通配符进行模糊匹配。

例如:

@Query("SELECT e FROM Employee e WHERE e.name LIKE %?1%") List<Employee> findByName(String name);

总结提升

根据自己的业务需求去选择使用哪一种模糊查询的方式。底层原理都是一样的。

JPA封装了一些公共的内容,我们开发的过程中使用起来就比较容易和简单。

但是我们在使用的过程中也要明白底层是如何实现,不能只停留在会使用的阶段中。知其然也要知其所以然。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot整合Swagger3生成接口文档过程解析

    SpringBoot整合Swagger3生成接口文档过程解析

    这篇文章主要介绍了SpringBoot整合Swagger3生成接口文档过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • JDBC使用小结

    JDBC使用小结

    JDBC是一个Java应用程序接口,作用是封装了对数据库的各种操作。JDBC由类和接口组成,使用Java开发数据库应用都需要4个主要的接口:Driver、Connection、Statement、ResultSet,这些接口定义了使用SQL访问数据库的一般架构,下面我们来详细探讨下jdbc的使用。
    2016-05-05
  • java秒杀系统常见问题库存超卖解决实例分析

    java秒杀系统常见问题库存超卖解决实例分析

    这篇文章主要为大家介绍了java秒杀系统常见问题库存超卖解决实例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 深入理解Java编程中异常处理的优劣

    深入理解Java编程中异常处理的优劣

    本篇文章是对Java编程中异常处理的优劣进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 浅析Spring配置文件

    浅析Spring配置文件

    本文主要对Spring配置文件进行了介绍。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • Java中内存异常StackOverflowError与OutOfMemoryError详解

    Java中内存异常StackOverflowError与OutOfMemoryError详解

    这篇文章主要介绍了 Java中内存异常StackOverflowError与OutOfMemoryError详解的相关资料,需要的朋友可以参考下
    2017-03-03
  • java实现网页爬虫的示例讲解

    java实现网页爬虫的示例讲解

    下面小编就为大家带来一篇java实现网页爬虫的示例讲解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 深度解析Java中volatile的内存语义实现以及运用场景

    深度解析Java中volatile的内存语义实现以及运用场景

    这篇文章主要介绍了Java中volatile的内存语义实现以及运用场景,通过JVM的机制来分析volatile关键字在线程编程中的作用,需要的朋友可以参考下
    2015-12-12
  • Springboot通过url访问本地图片代码实例

    Springboot通过url访问本地图片代码实例

    这篇文章主要介绍了springboot通过url访问本地图片代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java java.lang.ExceptionInInitializerError 错误如何解决

    Java java.lang.ExceptionInInitializerError 错误如何解决

    这篇文章主要介绍了 Java java.lang.ExceptionInInitializerError 错误如何解决的相关资料,需要的朋友可以参考下
    2017-06-06

最新评论