检索示例

如果您还没有阅读 介绍 > 为什么用 章节,建议先阅读它们。

查询方法

为便于下文示例讲解,我们首先需要一个 SearchBean,并假设 Bean Searcher 的可配置项都是默认值。

public class User {         // 对应数据库中的 user 表
    private Long id;        // ID 
    private String name;    // 姓名
    private int age;        // 年龄
    private int point;      // 积分
    // Getter and Setter ...
}
1
2
3
4
5
6
7

分页查询

不带参数时,默认查询 15 条数据(因为 默认分页大小为 15 ,可配置):

// 执行一条 SQL,默认查询 15 条数据
List<User> users = searcher.searchList(User.class, null);
1
2

查询第 2 页,每页 20 条(page 和 size 的参数名可配置):

Map<String, Object> params = MapUtils.builder()
        .page(1, 20)
        .build();
// 执行 1 条 SQL
List<User> users = searcher.searchList(User.class, params);
1
2
3
4
5

分页检索时,返回分页信息:

// 执行 2 条 SQL
SearchResult<User> result = searcher.search(User.class, params);
// 用户列表
List<User> users = result.getDataList();
// 数据总条数
Number totalCount = result.getTotalCount();
1
2
3
4
5
6

全量查询

Sercher 实例的 searchAll 方法可检索满足条件的所有数据:

Map<String, Object> params = MapUtils.builder()
        // 构造条件...
        .build();
// 向 params 添加检索条件, 比如按某个字段检索..
// 执行 1 条 SQL,不分页
List<User> result = searcher.searchAll(User.class, params);
1
2
3
4
5
6

对象查询

Sercher 实例的 searchFirst 方法可检索满足条件的第一个数据:

Map<String, Object> params = MapUtils.builder()
        // 构造条件...
        .build();
// 向 params 添加检索条件, 比如按某个字段检索..
// 执行 1 条 SQL,limit 1
User user = searcher.searchFirst(User.class, params);
1
2
3
4
5
6

统计查询

单字段统计:

Map<String, Object> params = MapUtils.builder()
        // 构造条件...
        .build();
// 执行 1 条 SQL,返回满足条件的用户的总年龄
Number totalAge = searcher.searchSum(User.class, params, "age");
1
2
3
4
5

多字段统计:

Map<String, Object> params = MapUtils.builder()
        // 构造条件...
        .build();
// 执行 1 条 SQL
Number[] summaries = searcher.searchSum(User.class, params, new String[] { "age", "point" });
Number totalAge = summaries[0];                 // 满足条件的用户总年龄
Number totalPoint = summaries[1];               // 满足条件的用户总积分
1
2
3
4
5
6
7

分页列表检索时顺带统计:

Map<String, Object> params = MapUtils.builder()
        // 构造条件...
        .build();
// 执行 2 条 SQL
SearchResult<User> result = searcher.search(User.class, params, new String[] { "age" });
List<User> users = result.getDataList();        // 用户列表
Number[] summaries = result.getSummaries();     // 统计信息
1
2
3
4
5
6
7

检索方式

不同的检索方式,只是调用 Sercher 实例的检索方法时传递的第二个 Map<String, Object> 类型的参数不同而已,所以为了简化文档,下文示例代码中只列出检索参数的组装过程,不再赘述 Sercher 实例的方法的调用。

参考:参数 > 字段参数 > 字段运算符 章节。

精确查询

以例说明,查询 age 等于 18 的用户:

Map<String, Object> params = MapUtils.builder()
        .field(User::getAge, 18).op(Equal.class)
        .build();
// ...
1
2
3
4

范围查询

以例说明,查询 age 大于 18 的用户:

Map<String, Object> params = MapUtils.builder()
        .field(User::getAge, 18).op(GreaterThan.class)      // age >  18
        .field(User::getAge, 18).op(GreaterEqual.class)     // age >= 18
        .field(User::getAge, 18).op(LessThan.class)         // age <  18
        .field(User::getAge, 18).op(LessEqual.class)        // age <= 18
        .field(User::getAge, 18).op(NotEqual.class)         // age != 18
        .field(User::getAge, 10, 20).op(Between.class)      // 10 <= age <= 20
        .build();  
// ...
1
2
3
4
5
6
7
8
9

模糊查询

以例说明,查询 name 包含字符串 'A' 的用户:

Map<String, Object> params = MapUtils.builder()
        .field(User::getName, "A").op(Contain.class)    // 包含 A
        .field(User::getName, "A").op(StartWith.class)  // 以 A 开头
        .field(User::getName, "A").op(EndWith.class)    // 以 A 结尾
        .field(User::getName, "A%", "%B", "%C%").op(OrLike.class)  // 以 A 开头 或 以 B 结尾 或 包含 C
        .build();
1
2
3
4
5
6

多值查询

以例说明,查询 id 等于 1 和 2 和 3 的用户:

Map<String, Object> params = MapUtils.builder()
        .field(User::getId, 1, 2, 3).op(InList.class)
        .build();
// ...
1
2
3
4

非空查询

以例说明,查询 name 不为空的用户:

Map<String, Object> params = MapUtils.builder()
        .field(User::getName).op(NotEmpty.class)
        .build();
// ...
1
2
3
4

动态检索

参考:参数 > 内嵌参数 章节。

分表检索

某订单系统的数据量非常巨大,如果把所有数据都放在一张表内,查询时经常会产生一些慢 SQL,检索时间长用户体验非常差。为了缓解这个问题,我们可以按年度把订单数据放在不同的表内,例如:

  • order_2018 存放 2018 年的订单
  • order_2019 存放 2019 年的订单
  • order_2020 存放 2020 年的订单
  • order_2021 存放 2021 年的订单

此时,我们的 SearchBean 可以这样定义:

@SearchBean(
    tables = ":table: o, user u",      // 参数 table 由检索时动态指定
    where = "o.user_id = u.id", autoMapTo = "o"
)
public class Order {
    private Long id;
    private String orderNo;
    @DbField("u.username")
    private String username;
    // 省略其它 ...
}
1
2
3
4
5
6
7
8
9
10
11

然后,后台订单管理系统加载数据时,同样只需几行代码便可轻松搞定:

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private BeanSearcher beanSearcher;

    /**
     * 订单检索接口
     * @param year 查询的订单年份,如:2018,2019
     **/
    @GetMapping("/index")
    public SearchResult<Order> index(HttpServletRequest request, int year) {
        Map<String, Object> params = MapUtils.flatBuilder(request.getParameterMap())
                .put("table", "order_" + year)              // 根据年份指定查询订单的表名
                .build();
        return beanSearcher.search(Order.class, params);    // 开始检索,并返回数据
    }
	
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

动态字段

参见 实体类 > 嵌入参数 > 嵌入到 @DbField 章节,字段参数 field 同样在检索参数中指定即可。