基于注解的MyBatis-Plus查询条件构建工具

为开发者提供一种声明式构建查询条件的快捷方式。

MyBatis-Plus-Query

简介

基于注解的MyBatis-Plus查询条件构建工具,为开发者提供一种声明式构建查询条件的快捷方式。

特性

  • 全面性:满足大部分条件构建的开发需求

  • 灵活、可扩展:支持条件补充、自定义校验规则、自定义查询条件或自定义处理器等

  • 安全:fail-fast机制防止错误数据的进一步处理

  • 性能优化:适当的数据缓存以及微妙级的性能损耗

  • 良好的测试覆盖率:行覆盖率、方法覆盖率和类覆盖率都在79%及以上

版本

  • JDK8 或更高版本

  • MyBatis-Plus 3.5.0 或更高版本

使用

  1. 添加依赖

首先,确保您的项目中已经添加了MyBatis-Plus依赖,其次将MyBatis-Plus-Query添加到您的项目中。

<!-- mybatis-plus-query -->
<dependency>
    <groupId>site.lianwu</groupId>
    <artifactId>mybatis-plus-query</artifactId>
    <version>1.2.0</version>
</dependency>
  1. 使用注解

@Query用于声明一个查询条件,可重复作用在字段上,而@NestedQuery用于声明一个待嵌套解析的字段。

@Data
public class UserDto {


    @Query(column = "email", value = ConditionType.Like.class, logic = Logic.OR, groupId = "KEYWORD")
    @Query(column = "name", value = ConditionType.Like.class, logic = Logic.OR, groupId = "KEYWORD")
    private String keyword;

    @NestedQuery
    private UserDto2 userDto2;

}

@Data
public class UserDto2 {

    @Query(ConditionType.Le.class)
    private Integer age;

}
  1. 构建并执行查询

    UserDto userDto = new UserDto();
    userDto.setKeyword("test");
    UserDto2 userDto2 = new UserDto2();
    userDto2.setAge(18);
    userDto.setUserDto2(userDto2);

    QueryOption<User> option = QueryOption.<User>builder()
        // 根组条件补充
        .withPostProcessor(wrapper -> {
            wrapper.lambda().eq(User::getId, 1);
        })
        // 指定"KEYWORD"组条件补充
        .withPostProcessor("KEYWORD", wrapper -> {
            wrapper.lambda().or().ge(User::getBirthday, LocalDate.of(2005, 1, 1));
        }).build();

    QueryWrapper<User> wrapper = QueryWrappers.parse(userDto, option);
    // WHERE (age <= 18 AND id = 1 AND (email LIKE '%test%' OR name LIKE '%test%' OR birthday >= '2005-01-01'))
    userService.list(wrapper);

更多示例:mybatis-plus-query-sample

原理

  1. 注解驱动:开发者通过在字段上使用@Query和@NestedQuery注解以定义查询逻辑。

  2. 条件解析:在构建查询时,MyBatis-Plus-Query会遍历条件对象的所有字段,提取并解析带有@Query和@NestedQuery注解的字段,最终生成MP的QueryWrapper条件包装。

    • 对于@Query中的属性值:

      • value:查询条件的比较方式,默认Eq(=)

      • column:指定条件列名,默认将字段名驼峰转下划线

      • logic:逻辑操作符,默认(and),表示分组条件间的逻辑关系

      • groupId:分组ID(分组是对SQL中括号的抽象),默认根组,即查询条件最外层括号 WHERE (...)

      • validation:校验规则,默认字段值不为空并且字符串不为空白,校验通过的字段值才参与条件构建

    • 对于@NestedQuery中的属性值:

      • value:是否包含继承字段,默认不包含

以默认的条件包装处理器为例,解析过程中优先处理根分组,其次处理其余分组,分组约定使用and连接。

由于底层使用了无序的数据结构,意味着对其余分组的处理是无序的,同样地,分组的条件设置也是无序的。

因此,若使用or逻辑条件处理,为确保查询结果的正确性,建议为这些or查询条件声明一个单独的分组。

其他/扩展

  • 数据缓存:MyBatis-Plus-Query默认实现了对查询类提取以及校验类、查询条件类实例获取的缓存,以提高条件构建效率。

  • 条件补充:解析过程中允许用户添加额外的查询条件,通过使用QueryOption的Builder补充不同分组的后置处理器以补充查询逻辑,在默认的处理器中,后置处理器只针对查询注解中声明的分组有效。这意味着即使补充了某个分组的后置处理逻辑,若该分组未在注解中声明,则相应的后置处理逻辑也不会被执行

  • 自定义校验规则/查询条件:开发者可自定义校验类(实现Validation接口)或自定义查询条件类(实现Condition接口),在@Query相应的属性值中指定类对象,以满足业务需求。

  • 插件式处理器:开发者可以自定义处理器(实现QueryFieldProcessor、QueryClassProcessor或QueryWrapperProcessor接口),在外观工具类QueryWrappers中实现插件式的组装,以支持个性化查询需求。

鸣谢

Gary(zjn)、Link(lsb)、Lauv(lyh)

License

Apache License 2.0


v1.2.0 - 2024/10/15

  • 重构反射工具

  • 调整缓存策略(缓存加工后的查询类而不缓存原始类的字段信息)

  • 调整默认的值校验器(不为空对象,空集合和空字符串)

  • 更新注释及README文档


v1.1.1 - 2024/08/17

  • 移除默认查询类处理器的缓存特性,并增加带缓存的查询类处理器供用户选择

  • 条件解析工具默认不再缓存查询类


v1.1.0 - 2024/07/19

  • 补充安全的查询类处理器,支持检测循环引用,默认使用该处理器进行提取和解析

  • 更正部分代码注释

Comment