检索示例
查询方法
为便于下文示例讲解,我们首先定义一个 SearchBean,并假设 Bean Searcher 的可配置项都是默认值。
@SearchBean(tables = "user")
public class User {
@DbField("id")
private Long id; // ID
@DbField("name")
private String name; // 姓名
@DbField("age")
private int age; // 年零
@DbField("point")
private int point; // 积分
// Getter and Setter ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
分页查询
不带参数时,默认查询 15 条数据(因为 默认分页大小为 15 ,可配置):
// 执行一条 SQL,默认查询 15 条数据
List<User> users = searcher.searchList(User.class, new HashMap<>());
2
查询第 2 页,每页 20 条(page 和 size 的参数名可配置):
Map<String, Object> params = new HashMap<>();
params.put("page", 1);
params.put("size", 20);
// 执行 1 条 SQL
List<User> users = searcher.searchList(User.class, params);
2
3
4
5
分页检索时,返回分页信息:
// 执行 2 条 SQL
SearchResult<User> result = searcher.search(User.class, params);
// 用户列表
List<User> users = result.getDataList();
// 数据总条数
Number totalCount = result.getTotalCount();
// 总页数
Number totalPage = result.getTotalPage();
// 当前页数
Number page = result.getPage();
2
3
4
5
6
7
8
9
10
全量查询
Sercher 实例的 searchAll
方法可检索满足条件的所有数据:
Map<String, Object> params = new HashMap<>();
// 向 params 添加检索条件, 比如按某个字段检索..
// 执行 1 条 SQL,不分页
List<User> result = searcher.searchAll(User.class, params);
2
3
4
对象查询
Sercher 实例的 searchFirst
方法可检索满足条件的第一个数据:
Map<String, Object> params = new HashMap<>();
// 向 params 添加检索条件, 比如按某个字段检索..
// 执行 1 条 SQL,limit 1
User user = searcher.searchFirst(User.class, params);
2
3
4
统计查询
单字段统计:
// 执行 1 条 SQL,返回满足条件的用户的总年龄
Number totalAge = searcher.searchSum(User.class, params, "age");
2
多字段统计:
// 执行 1 条 SQL
Number[] summaries = searcher.searchSum(User.class, params, new String[] { "age", "point" });
Number totalAge = summaries[0]; // 满足条件的用户总年龄
Number totalPoint = summaries[1]; // 满足条件的用户总积分
2
3
4
分页列表检索时顺带统计:
// 执行 2 条 SQL
SearchResult<User> result = searcher.search(User.class, params, new String[] { "age" });
List<User> users = result.getDataList(); // 用户列表
Number[] summaries = result.getSummaries(); // 统计信息
2
3
4
检索方式
不同的检索方式,只是调用 Sercher 实例的检索方法时传递的第二个 Map<String, Object>
类型的参数不同而已,所以为了简化文档,下文示例代码中只列出检索参数的组装过程,不再赘述 Sercher 实例的方法的调用。
精确查询
以例说明,查询 age
等于 18 的用户:
Map<String, Object> params = new HashMap<>();
params.put("age", 18);
params.put("age-op", "eq");
// ...
2
3
4
范围查询
以例说明,查询 age
大于 18 的用户:
Map<String, Object> params = new HashMap<>();
params.put("age", 18);
params.put("age-op", "gt"); // gt: 大于,ge: 大于等于,lt: 小于,le: 小于等于,ne: 不等于
// ...
2
3
4
模糊查询
以例说明,查询 name
包含字符串 'Alice'
的用户:
Map<String, Object> params = new HashMap<>();
params.put("name", 'Alice');
params.put("name-op", "in"); // in: 包含,sw: 以...开头,ew: 以...结尾
params.put("name-ic", true); // 同时可以指定是否可以忽略大小写
// ...
2
3
4
5
区间查询
以例说明,查询 age
在 18 与 30 之间的用户:
Map<String, Object> params = new HashMap<>();
params.put("age-0", 18);
params.put("age-1", 30);
params.put("age-op", "bt"); // 区间查询,age 字段 2 个值
// 查询在 18 与 30 之间的用户(包含边界)
2
3
4
5
当 age
字段的参数值只有一个,或第二个参数值为 null 时,Between
运算符查询大于等于第一个参数值的数据:
Map<String, Object> params = new HashMap<>();
params.put("age", 18);
params.put("age-op", "bt"); // 区间查询,name 字段有 1 个值,或第 2 个为 null
// 查询大于等于 18 的用户
2
3
4
当 age
字段的参数值有两个,但 第一个为 null
时,Between
运算符查询小于等于第二个参数值的数据:
Map<String, Object> params = new HashMap<>();
params.put("age-0", null);
params.put("age-1", 30);
params.put("age-op", "bt"); // 区间查询,age 字段有 2 个值,但第 1 个为 null
// 查询小于等于 30 的用户
2
3
4
5
当 age
的参数值超多 2 个时,Between
运算符只使用前两个参数值,会忽略其它参数值。
TIP
Bean Searcher 判断参数值的顺序是根据 age-{n}
里面的序号 n
判断的,与代码的顺序无关。
多值查询
以例说明,查询 name
等于 Jack 和 Tom 和 Alice 的用户:
Map<String, Object> params = new HashMap<>();
params.put("name-0", 'Jack');
params.put("name-1", 'Tom');
params.put("name-2", 'Alice');
params.put("name-op", "mv"); // 多值查询,name 字段有多个值
// ...
2
3
4
5
6
非空查询
以例说明,查询 name
不为空的用户:
Map<String, Object> params = new HashMap<>();
params.put("name-op", "ny"); // ey: 为空,ny: 不为空
// ...
2
3
动态检索
分表检索
某订单系统的数据量非常巨大,如果把所有数据都放在一张表内,查询时经常会产生一些慢 SQL,检索时间长用户体验非常差。为了缓解这个问题,我们可以按年度把订单数据放在不同的表内,例如:
- 表
order_2018
存放 2018 年的订单 - 表
order_2019
存放 2019 年的订单 - 表
order_2020
存放 2020 年的订单 - 表
order_2021
存放 2021 年的订单
此时,我们的 SearchBean 可以这样定义:
@SearchBean(
tables = ":table: o, user u", // 参数 table 由检索时动态指定
joinCond = "o.user_id = u.id" // 实际项目中可能还会关联其它表
)
public class Order {
@DbField("o.id")
private long id;
@DbField("o.order_no")
private String orderNo;
@DbField("u.username")
private String username;
// 其它字段 ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
然后,后台订单管理系统加载数据时,同样只需几行代码便可轻松搞定:
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private Searcher searcher;
/**
* 订单检索接口
* @param year 查询的订单年份,如:2018,2019
**/
@GetMapping("/index")
public Object index(HttpServletRequest request, int year) {
// 收集其它检索参数
Map<String, Object> params = MapUtils.flat(request.getParameterMap());
// 根据年份指定查询订单的表名
params.put("table", "order_" + year);
// 开始检索,并返回数据
return searcher.search(Order.class, params);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
动态字段
参见 实体类 > 嵌入参数 > 嵌入到 @DbField 章节,字段参数 field
同样在检索参数中指定即可。