Spring Data JPA QueryByExampleExecutor如何高效运用实例解析?

2026-06-10 20:32:59 150阅读 0评论 SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3200个文字,预计阅读时间需要13分钟。

目录

1.QueryByExampleExecutor用法

Spring Data JPA QueryByExampleExecutor如何高效运用实例解析?

1.1. 介绍 1.2. QueryByExampleExecutor接口 1.3. QueryByExampleExecutor实践 1.4. Example语法详解 1.5. ExampleMatcher语法分析

2.ExampleMatcher语法常用方法

2.1. 忽略大小写 2.2. N“

Spring Data JPA QueryByExampleExecutor如何高效运用实例解析?

目录
  • 1、QueryByExampleExecutor用法
    • 1.1 介绍
    • 1.2 QueryByExampleExecutor接口
    • 1.3 QueryByExampleExecutor实践
    • 1.4 Example语法详解
    • 1.5 ExampleMatcher语法分析
  • 2、ExampleMatcher语法暴露常用方法
    • 2.1 忽略大小写
    • 2.2 NULL值的Property的处理方式
    • 2.3 忽略某些属性列表,不参与查询过滤条件
    • 2.4 字符串默认的匹配规则
  • 3、实践出真理
    • 3.1 AND查询
    • 3.2 OR 查询
    • 3.3 忽略大小写查询
      • 3.3.1 忽略大小写 不指定属性
    • 3.4 NULL值的处理
      • 3.4.1 NULL属性值作为查询条件
      • 3.4.2 忽略(实体类中)NULL属性
    • 3.5 忽略某些属性不做筛选
      • 3.6 字符串匹配规则
        • 3.6.1 DEFAULT和EXACT 相等
        • 3.6.2 STARTING和ENDING 模糊查询
        • 3.6.3 Containing 包含模糊匹配

    1、QueryByExampleExecutor用法

    在前面章节中,我们介绍了DMQ 和 @Query两种查询方法,除此之外,还有QueryByExampleExecutor查询方法。

    1.1 介绍

    QueryByExampleExecutor是一种用户友好的查询技术,具有简单的接口,它允许动态创建,并且不需要填写包含字段名称的查询。

    1.2 QueryByExampleExecutor接口

    public interface QueryByExampleExecutor<T> { // 根据实体查询条件、查找一个对象 <S extends T> Optional<S> findOne(Example<S> example); // 根据实体查询条件、查询一批对象 <S extends T> Iterable<S> findAll(Example<S> example); // 根据实体查询条件并排序、查询一批对象 <S extends T> Iterable<S> findAll(Example<S> example, Sort sort); // 根据实体查询条件并分页,查询一批对象 <S extends T> Page<S> findAll(Example<S> example, Pageable pageable); // 根据实体查询条件、查询符合条件的对象个数 <S extends T> long count(Example<S> example); // 根据实体查询条件、判断是否有符合条件的对象 <S extends T> boolean exists(Example<S> example); // 根据实体查询条件、判断是否有符合条件的对象 <S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction); }

    1.3 QueryByExampleExecutor实践

    第一步 :创建User实体和UserAddress实体

    // User表 @Data @Entity @NoArgsConstructor @AllArgsConstructor @Builder @ToString(exclude = "address") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String email; private Integer age; private LocalDateTime createTime; private LocalDateTime updateTime; @OneToMany(mappedBy = "user",fetch = FetchType.LAZY) private List<UserAddress> address; } // Address表 @Entity @Data @Builder @AllArgsConstructor @NoArgsConstructor @ToString(exclude = "user") public class UserAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String address; @ManyToOne(cascade = CascadeType.ALL) private User user; }

    第二步: 编写DAO层,JpaRepository已经继承QueryByExampleExceutor

    public interface UserAddressRepo extends JpaRepository<UserAddress,Integer> { }

    第三步:测试

    @Test public void test01 () { User user = User.builder() .name("jack") .email("123456@126.com") .age(20) .build(); userAddressRepo.saveAll(Lists.newArrayList(UserAddress.builder() .address("shanghai").user(user).build(),UserAddress.builder() .address("beijing").user(user).build())); } @Test public void testQBEE() throws JsonProcessingException { User user = User.builder() .name("jack") .age(20) .email("12345") .build(); UserAddress userAddress = UserAddress.builder() .address("shanghai") .user(user) .build(); ObjectMapper objectMapper = new ObjectMapper(); // 创建匹配器,构建动态查询条件 ExampleMatcher exampleMatcher = ExampleMatcher.matching() .withMatcher("user.email",ExampleMatcher.GenericPropertyMatchers.startsWith()) .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.startsWith()); Page<UserAddress> u = userAddressRepo.findAll(Example.of(userAddress,exampleMatcher), PageRequest.of(0,2)); System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(u)); }

    一开始写这个代码的时候,我也比较懵逼, Example是什么?ExampleMatcher是什么? 下面我一一介绍。

    1.4 Example语法详解

    首先:我们先看Example的源码

    public interface Example<T> { static <T> Example<T> of(T probe) { return new TypedExample<>(probe, ExampleMatcher.matching()); } static <T> Example<T> of(T probe, ExampleMatcher matcher) { return new TypedExample<>(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); @SuppressWarnings("unchecked") default Class<T> getProbeType() { return (Class<T>) ProxyUtils.getUserClass(getProbe().getClass()); } }

    • probe:实际实体类,即查询条件的封装类(又可以理解为查询条件参数)
    • ExampleMatcher :匹配器,匹配特定字段的匹配规则。
    • Example:由probe 和 ExampleMatcher租车,由于创建查询,即组合查询参数和参数的匹配规则。

    创建Example的两个方法 :

    • static Example of(T probe):需要一个实体参数,即查询条件。而里面的ExampleMatcher采用默认的ExamoleMatcher.matching(); 表示忽略NULL,所有字段采用精准匹配
    • static Example of(T probe, ExampleMatcher matcher):需要两个参数构建Example,也就表示ExampleMatcher自由组合规则,正如我们上面的测试用例里面的代码一样。

    1.5 ExampleMatcher语法分析

    上图是ExampleMatcher向外暴露的方法,我们只要关心返回值为ExampleMatcher类型的方法。

    其中有三个方法我们需要注意一下:

    static ExampleMatcher matching() { return matchingAll(); } static ExampleMatcher matchingAll() { return new TypedExampleMatcher().withMode(MatchMode.ALL); }

    上述的这两种方法表达的意思是一样的。两者采用的都是MatcheMode.ALL的模式,即AND模式,生成的SQL如下:

    Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where (useraddres0_.address like ? escape ?) and user1_.name=? and (user1_.email like ? escape ?) and user1_.age=20

    可以看到,这些查询条件都是AND的关系。再看另外一种方法

    static ExampleMatcher matchingAny() { return new TypedExampleMatcher().withMode(MatchMode.ANY); }

    当前方法与上面两个方法不一样的地方在于:第三个MatchMode.Any,表示查询条件是or的关系

    Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.age=20

    以上就是初始化ExampleMatcher实例的方法,你在运用中需要注意and 和 or的关系

    2、ExampleMatcher语法暴露常用方法

    2.1 忽略大小写

    // 哪些属性的paths忽略大小写,可以指定多个参数 ExampleMatcher withIgnoreCase(String... propertyPaths); // 提供一个默认的实现方法,忽略大小写 default ExampleMatcher withIgnoreCase() { return withIgnoreCase(true); } // 默认忽略大小写的方式,默认false ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase);

    2.2 NULL值的Property的处理方式

    暴露的Null值处理方式如下所示:

    ExampleMatcher withNullHandler(NullHandler nullHandler);

    NullHandler枚举值如下所示:INCLUDE(包括)、IGNORE(忽略),

    enum NullHandler { INCLUDE, IGNORE }

    需要注意的是: 标识作为条件的实体对象中,一个属性值(条件值)为NULL时,是否参与过滤;
    当该选项值是INCLUDE时,标识仍参与过滤,会匹配数据库表中该字段值是NULL的记录;

    若为IGNORE值,表示不参与过滤;

    // 把(实体类中)NULL属性值作为查询条件 default ExampleMatcher withIncludeNullValues() { return withNullHandler(NullHandler.INCLUDE); } // 提供一个默认实现方法,忽略(实体类中)NULL属性 default ExampleMatcher withIgnoreNullValues() { return withNullHandler(NullHandler.IGNORE); }

    我们来看一下,把(实体类中)NULL属性值作为查询条件使用,执行的SQL如下所示:

    Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.id is null or useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.id is null or user1_.age=20

    2.3 忽略某些属性列表,不参与查询过滤条件

    // 忽略某些属性(可以是多个),不参与查询过滤条件 ExampleMatcher withIgnorePaths(String... ignoredPaths);

    2.4 字符串默认的匹配规则

    ExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher);

    默认字符串的匹配方式有以下几种 ,如下所示:

    enum StringMatcher { DEFAULT, EXACT, STARTING, ENDING, CONTAINING, REGEX; }

    DEFAULT:默认,作用和EXACT一样
    EXACT:相等
    STARTING:开始匹配
    ENDING:结束匹配
    CONTAINING:包含、模糊匹配
    REGEX:正则表达式

    使用方法如下

    withStringMatcher(ExampleMatcher.StringMatcher.ENDING)

    或指定某些字符串属性匹配规则

    ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher);

    3、实践出真理

    就从上面介绍的方法,我们手动练习一下。

    新建一张Dog表

    @Data @Entity @AllArgsConstructor @NoArgsConstructor @Table(name = "tb_dog") public class Dog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(columnDefinition = "int(11) NOT NULL COMMENT '主键' ") private Integer id; @Column(columnDefinition = "varchar(30) DEFAULT '' COMMENT '宠物名'") private String name; @Column(columnDefinition = "int(11) DEFAULT NULL COMMENT '年龄'") private Integer age; }

    3.1 AND查询

    解释:根据当前dog对象的属性值作为查询条件去查询

    @Test public void testBy01(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // AND 查询 ExampleMatcher matcher = ExampleMatcher.matching(); //ExampleMatcher.matchingAll() 也可以 System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    Hibernate: select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2

    3.2 OR 查询

    解释:根据当前dog对象的属性值作为查询条件去查询

    @Test public void testBy02(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // OR 查询 ExampleMatcher matcher = ExampleMatcher.matchingAny(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? or dog0_.age=2

    3.3 忽略大小写查询

    解释:指定"name"属性忽略大小写

    @Test public void testBy03(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase("name"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where lower(dog0_.name)=? and dog0_.age=2

    在Dog表中添加type字段

    @Column(columnDefinition = "varchar(20) DEFAULT NULL COMMENT '种类'") private String type;

    3.3.1 忽略大小写 不指定属性

    解释:不指定属性,默认为所有查询字符串条件加上忽略大小写条件

    @Test public void testBy04(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.name)=? and lower(dog0_.type)=? and dog0_.age=2

    3.4 NULL值的处理

    3.4.1 NULL属性值作为查询条件

    解释:把(实体类中)NULL属性值作为查询条件使用

    @Test public void testBy05(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase() .withIncludeNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.type)=? and (dog0_.id is null) and dog0_.age=2 and lower(dog0_.name)=?

    3.4.2 忽略(实体类中)NULL属性

    解释:把(实体类中)NULL属性值忽略

    @Test public void testBy06(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.type=? and dog0_.age=2

    3.5 忽略某些属性不做筛选

    解释:把(实体类中)某些属性忽略掉,不做筛选

    @Test public void testBy07(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); // 忽略掉"name" 和 "type"两个属性 ExampleMatcher matcher = ExampleMatcher.matching() .withIgnorePaths("name","type"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2

    3.6 字符串匹配规则

    3.6.1 DEFAULT和EXACT 相等

    解释:把(实体类中)所有字符串属性匹配规则设置为 EXACT (相等)

    @Test public void testBy08(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 字符串属性提供的匹配规则 EXACT相等 .withStringMatcher( ExampleMatcher.StringMatcher.EXACT); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2 and dog0_.type=?

    3.6.2 STARTING和ENDING 模糊查询

    解释:把(实体类中)所有字符串属性匹配规则设置为 STARTING/ENDING (模糊查询)

    public void testBy09(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 设置为开始匹配 .withStringMatcher(ExampleMatcher.StringMatcher.STARTING); // 设置为结束匹配 //.withStringMatcher(ExampleMatcher.StringMatcher.ENDING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)

    3.6.3 Containing 包含模糊匹配

    解释:把(实体类中)所有字符串属性匹配规则设置为 Containing (包含模糊查询)

    @Test public void testBy11(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 包含模糊查询 .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

    执行SQL结果如下所示:

    select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)

    以上就是Spring Data JPA系列QueryByExampleExecutor使用详解的详细内容,更多关于Spring Data JPA QueryByExampleExecutor的资料请关注自由互联其它相关文章!

    标签: 高效 实例 data

    本文共计3200个文字,预计阅读时间需要13分钟。

    目录

    1.QueryByExampleExecutor用法

    Spring Data JPA QueryByExampleExecutor如何高效运用实例解析?

    1.1. 介绍 1.2. QueryByExampleExecutor接口 1.3. QueryByExampleExecutor实践 1.4. Example语法详解 1.5. ExampleMatcher语法分析

    2.ExampleMatcher语法常用方法

    2.1. 忽略大小写 2.2. N“

    Spring Data JPA QueryByExampleExecutor如何高效运用实例解析?

    目录
    • 1、QueryByExampleExecutor用法
      • 1.1 介绍
      • 1.2 QueryByExampleExecutor接口
      • 1.3 QueryByExampleExecutor实践
      • 1.4 Example语法详解
      • 1.5 ExampleMatcher语法分析
    • 2、ExampleMatcher语法暴露常用方法
      • 2.1 忽略大小写
      • 2.2 NULL值的Property的处理方式
      • 2.3 忽略某些属性列表,不参与查询过滤条件
      • 2.4 字符串默认的匹配规则
    • 3、实践出真理
      • 3.1 AND查询
      • 3.2 OR 查询
      • 3.3 忽略大小写查询
        • 3.3.1 忽略大小写 不指定属性
      • 3.4 NULL值的处理
        • 3.4.1 NULL属性值作为查询条件
        • 3.4.2 忽略(实体类中)NULL属性
      • 3.5 忽略某些属性不做筛选
        • 3.6 字符串匹配规则
          • 3.6.1 DEFAULT和EXACT 相等
          • 3.6.2 STARTING和ENDING 模糊查询
          • 3.6.3 Containing 包含模糊匹配

      1、QueryByExampleExecutor用法

      在前面章节中,我们介绍了DMQ 和 @Query两种查询方法,除此之外,还有QueryByExampleExecutor查询方法。

      1.1 介绍

      QueryByExampleExecutor是一种用户友好的查询技术,具有简单的接口,它允许动态创建,并且不需要填写包含字段名称的查询。

      1.2 QueryByExampleExecutor接口

      public interface QueryByExampleExecutor<T> { // 根据实体查询条件、查找一个对象 <S extends T> Optional<S> findOne(Example<S> example); // 根据实体查询条件、查询一批对象 <S extends T> Iterable<S> findAll(Example<S> example); // 根据实体查询条件并排序、查询一批对象 <S extends T> Iterable<S> findAll(Example<S> example, Sort sort); // 根据实体查询条件并分页,查询一批对象 <S extends T> Page<S> findAll(Example<S> example, Pageable pageable); // 根据实体查询条件、查询符合条件的对象个数 <S extends T> long count(Example<S> example); // 根据实体查询条件、判断是否有符合条件的对象 <S extends T> boolean exists(Example<S> example); // 根据实体查询条件、判断是否有符合条件的对象 <S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction); }

      1.3 QueryByExampleExecutor实践

      第一步 :创建User实体和UserAddress实体

      // User表 @Data @Entity @NoArgsConstructor @AllArgsConstructor @Builder @ToString(exclude = "address") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String email; private Integer age; private LocalDateTime createTime; private LocalDateTime updateTime; @OneToMany(mappedBy = "user",fetch = FetchType.LAZY) private List<UserAddress> address; } // Address表 @Entity @Data @Builder @AllArgsConstructor @NoArgsConstructor @ToString(exclude = "user") public class UserAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String address; @ManyToOne(cascade = CascadeType.ALL) private User user; }

      第二步: 编写DAO层,JpaRepository已经继承QueryByExampleExceutor

      public interface UserAddressRepo extends JpaRepository<UserAddress,Integer> { }

      第三步:测试

      @Test public void test01 () { User user = User.builder() .name("jack") .email("123456@126.com") .age(20) .build(); userAddressRepo.saveAll(Lists.newArrayList(UserAddress.builder() .address("shanghai").user(user).build(),UserAddress.builder() .address("beijing").user(user).build())); } @Test public void testQBEE() throws JsonProcessingException { User user = User.builder() .name("jack") .age(20) .email("12345") .build(); UserAddress userAddress = UserAddress.builder() .address("shanghai") .user(user) .build(); ObjectMapper objectMapper = new ObjectMapper(); // 创建匹配器,构建动态查询条件 ExampleMatcher exampleMatcher = ExampleMatcher.matching() .withMatcher("user.email",ExampleMatcher.GenericPropertyMatchers.startsWith()) .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.startsWith()); Page<UserAddress> u = userAddressRepo.findAll(Example.of(userAddress,exampleMatcher), PageRequest.of(0,2)); System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(u)); }

      一开始写这个代码的时候,我也比较懵逼, Example是什么?ExampleMatcher是什么? 下面我一一介绍。

      1.4 Example语法详解

      首先:我们先看Example的源码

      public interface Example<T> { static <T> Example<T> of(T probe) { return new TypedExample<>(probe, ExampleMatcher.matching()); } static <T> Example<T> of(T probe, ExampleMatcher matcher) { return new TypedExample<>(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); @SuppressWarnings("unchecked") default Class<T> getProbeType() { return (Class<T>) ProxyUtils.getUserClass(getProbe().getClass()); } }

      • probe:实际实体类,即查询条件的封装类(又可以理解为查询条件参数)
      • ExampleMatcher :匹配器,匹配特定字段的匹配规则。
      • Example:由probe 和 ExampleMatcher租车,由于创建查询,即组合查询参数和参数的匹配规则。

      创建Example的两个方法 :

      • static Example of(T probe):需要一个实体参数,即查询条件。而里面的ExampleMatcher采用默认的ExamoleMatcher.matching(); 表示忽略NULL,所有字段采用精准匹配
      • static Example of(T probe, ExampleMatcher matcher):需要两个参数构建Example,也就表示ExampleMatcher自由组合规则,正如我们上面的测试用例里面的代码一样。

      1.5 ExampleMatcher语法分析

      上图是ExampleMatcher向外暴露的方法,我们只要关心返回值为ExampleMatcher类型的方法。

      其中有三个方法我们需要注意一下:

      static ExampleMatcher matching() { return matchingAll(); } static ExampleMatcher matchingAll() { return new TypedExampleMatcher().withMode(MatchMode.ALL); }

      上述的这两种方法表达的意思是一样的。两者采用的都是MatcheMode.ALL的模式,即AND模式,生成的SQL如下:

      Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where (useraddres0_.address like ? escape ?) and user1_.name=? and (user1_.email like ? escape ?) and user1_.age=20

      可以看到,这些查询条件都是AND的关系。再看另外一种方法

      static ExampleMatcher matchingAny() { return new TypedExampleMatcher().withMode(MatchMode.ANY); }

      当前方法与上面两个方法不一样的地方在于:第三个MatchMode.Any,表示查询条件是or的关系

      Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.age=20

      以上就是初始化ExampleMatcher实例的方法,你在运用中需要注意and 和 or的关系

      2、ExampleMatcher语法暴露常用方法

      2.1 忽略大小写

      // 哪些属性的paths忽略大小写,可以指定多个参数 ExampleMatcher withIgnoreCase(String... propertyPaths); // 提供一个默认的实现方法,忽略大小写 default ExampleMatcher withIgnoreCase() { return withIgnoreCase(true); } // 默认忽略大小写的方式,默认false ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase);

      2.2 NULL值的Property的处理方式

      暴露的Null值处理方式如下所示:

      ExampleMatcher withNullHandler(NullHandler nullHandler);

      NullHandler枚举值如下所示:INCLUDE(包括)、IGNORE(忽略),

      enum NullHandler { INCLUDE, IGNORE }

      需要注意的是: 标识作为条件的实体对象中,一个属性值(条件值)为NULL时,是否参与过滤;
      当该选项值是INCLUDE时,标识仍参与过滤,会匹配数据库表中该字段值是NULL的记录;

      若为IGNORE值,表示不参与过滤;

      // 把(实体类中)NULL属性值作为查询条件 default ExampleMatcher withIncludeNullValues() { return withNullHandler(NullHandler.INCLUDE); } // 提供一个默认实现方法,忽略(实体类中)NULL属性 default ExampleMatcher withIgnoreNullValues() { return withNullHandler(NullHandler.IGNORE); }

      我们来看一下,把(实体类中)NULL属性值作为查询条件使用,执行的SQL如下所示:

      Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.id is null or useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.id is null or user1_.age=20

      2.3 忽略某些属性列表,不参与查询过滤条件

      // 忽略某些属性(可以是多个),不参与查询过滤条件 ExampleMatcher withIgnorePaths(String... ignoredPaths);

      2.4 字符串默认的匹配规则

      ExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher);

      默认字符串的匹配方式有以下几种 ,如下所示:

      enum StringMatcher { DEFAULT, EXACT, STARTING, ENDING, CONTAINING, REGEX; }

      DEFAULT:默认,作用和EXACT一样
      EXACT:相等
      STARTING:开始匹配
      ENDING:结束匹配
      CONTAINING:包含、模糊匹配
      REGEX:正则表达式

      使用方法如下

      withStringMatcher(ExampleMatcher.StringMatcher.ENDING)

      或指定某些字符串属性匹配规则

      ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher);

      3、实践出真理

      就从上面介绍的方法,我们手动练习一下。

      新建一张Dog表

      @Data @Entity @AllArgsConstructor @NoArgsConstructor @Table(name = "tb_dog") public class Dog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(columnDefinition = "int(11) NOT NULL COMMENT '主键' ") private Integer id; @Column(columnDefinition = "varchar(30) DEFAULT '' COMMENT '宠物名'") private String name; @Column(columnDefinition = "int(11) DEFAULT NULL COMMENT '年龄'") private Integer age; }

      3.1 AND查询

      解释:根据当前dog对象的属性值作为查询条件去查询

      @Test public void testBy01(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // AND 查询 ExampleMatcher matcher = ExampleMatcher.matching(); //ExampleMatcher.matchingAll() 也可以 System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      Hibernate: select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2

      3.2 OR 查询

      解释:根据当前dog对象的属性值作为查询条件去查询

      @Test public void testBy02(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // OR 查询 ExampleMatcher matcher = ExampleMatcher.matchingAny(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? or dog0_.age=2

      3.3 忽略大小写查询

      解释:指定"name"属性忽略大小写

      @Test public void testBy03(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase("name"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where lower(dog0_.name)=? and dog0_.age=2

      在Dog表中添加type字段

      @Column(columnDefinition = "varchar(20) DEFAULT NULL COMMENT '种类'") private String type;

      3.3.1 忽略大小写 不指定属性

      解释:不指定属性,默认为所有查询字符串条件加上忽略大小写条件

      @Test public void testBy04(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.name)=? and lower(dog0_.type)=? and dog0_.age=2

      3.4 NULL值的处理

      3.4.1 NULL属性值作为查询条件

      解释:把(实体类中)NULL属性值作为查询条件使用

      @Test public void testBy05(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase() .withIncludeNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.type)=? and (dog0_.id is null) and dog0_.age=2 and lower(dog0_.name)=?

      3.4.2 忽略(实体类中)NULL属性

      解释:把(实体类中)NULL属性值忽略

      @Test public void testBy06(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.type=? and dog0_.age=2

      3.5 忽略某些属性不做筛选

      解释:把(实体类中)某些属性忽略掉,不做筛选

      @Test public void testBy07(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); // 忽略掉"name" 和 "type"两个属性 ExampleMatcher matcher = ExampleMatcher.matching() .withIgnorePaths("name","type"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2

      3.6 字符串匹配规则

      3.6.1 DEFAULT和EXACT 相等

      解释:把(实体类中)所有字符串属性匹配规则设置为 EXACT (相等)

      @Test public void testBy08(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 字符串属性提供的匹配规则 EXACT相等 .withStringMatcher( ExampleMatcher.StringMatcher.EXACT); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2 and dog0_.type=?

      3.6.2 STARTING和ENDING 模糊查询

      解释:把(实体类中)所有字符串属性匹配规则设置为 STARTING/ENDING (模糊查询)

      public void testBy09(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 设置为开始匹配 .withStringMatcher(ExampleMatcher.StringMatcher.STARTING); // 设置为结束匹配 //.withStringMatcher(ExampleMatcher.StringMatcher.ENDING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)

      3.6.3 Containing 包含模糊匹配

      解释:把(实体类中)所有字符串属性匹配规则设置为 Containing (包含模糊查询)

      @Test public void testBy11(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 包含模糊查询 .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }

      执行SQL结果如下所示:

      select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)

      以上就是Spring Data JPA系列QueryByExampleExecutor使用详解的详细内容,更多关于Spring Data JPA QueryByExampleExecutor的资料请关注自由互联其它相关文章!

      标签: 高效 实例 data