Mybatis-Plus基础之Mapper查询
Mybatis-mapper 的使用技巧
文章目录
一、简单查询
// 根据 ID 查询。执行的 SQL 条件是 id = ...
T selectById(Serializable id);
// 根据 ID 批量查询。执行的 SQL 条件是 id in (...)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据指定字段查询。执行 SQL 条件是 xxx=... and yyy=... and zzz=...
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
二、 分页查询
分压查询的接口(即,方法参数中要求传入 IPage 对象的)不能直接使用,需要配置后才可用。如果你没有配置就直接使用,你会发现执行的仍然是 select all 的效果。
-
配置:
@Bean // 确保 Spring IoC 容器中存在一个分页拦截器的 JavaBean 。 public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }
-
使用和验证:
Page<Employee> page = new Page<>(1, 2); Page<Employee> employeePage = employeeDao.selectPage(page, null); log.info(" 当前页码: {}", employeePage.getCurrent()); log.info("每页数据总量: {}", employeePage.getSize()); log.info(" 总页数: {}", employeePage.getPages()); log.info(" 总数据量: {}", employeePage.getTotal()); log.info("当前页数据据如下:"); employeePage.getRecords().forEach(item -> log.info("{}", item));
三、条件查询:Wrapper
在 Dao/Mapper “点”出来的 select 方法中,你会发现有大量的要求你传入 Wrapper 对象的查询方法,这些方法就是用来实现复杂的条件查询功能的,而 Wrapper 对象就是所谓的条件构造器。
Wrapper 查询所有
对于这些要求传入 Wrapper 对象的 select 方法,如果你故意在 Wrapper 参数位置传入一个 null ,那么就是『无条件查询所有』的功能。
Wrapper 查询的 3 种写法
# 写法一:常规写法(不推荐)
QueryWrapper<EmployeePo> qw = new QueryWrapper<>();
qw.lt("salary", 2000);
List<EmployeePo> pos = employeeDao.selectList(qw);
如果有多条件的话,除了独立式赋值,还可以用链式调用写法串在一起
// qw.lt("salary", 2000);
// qw.gt("commission", 500);
qw.lt("salary", 2000).gt("commission", 500);
缺点:查询条件中的列名是以字符串的形式给出的,万一写错了,debug 时找这种错十分费劲。
# 写法二:lambda 写法
QueryWrapper<EmployeePo> qw = new QueryWrapper<>();
qw.lambda().lt(EmployeePo::getSalary, 2000).gt(EmployeePo::getCommission, 500);
List<EmployeePo> pos = employeeDao.selectList(qw);
缺点:这个写法每次都要手动调用一次 .lambda()
方法。
# 写法三:另一种 lambda 写法(推荐)
LambdaQueryWrapper<EmployeePo> qw = new LambdaQueryWrapper<>();
qw.lt(EmployeePo::getSalary, 2000).gt(EmployeePo::getCommission, 500);
List<EmployeePo> pos = employeeDao.selectList(qw);
一个复杂一点的例子
按用户名和状态查询后台用户并按创建时间降序排列为例。预期执行的 SQL 应该如下:
SELECT
*
FROM
employee
WHERE
department_id = 2
AND
salary BETWEEN 500 AND 3000
ORDER BY
salary DESC;
在 mybatis-plus 中创建 Wrapper 对象,并调用对象的方法,例如,eq()
、between()
等方法来表达你所想的查询条件。这些条件之间是 AND 的关系:
构造 Wrapper 对象来表达你心里所想的查询条件和排序规则。
LambdaQueryWrapper<EmployeePo> lqw = new LambdaQueryWrapper<>();
lqw.eq(EmployeePo::getDepartmentId, 2L)
.between(EmployeePo::getSalary, 500, 3000)
.orderByDesc(EmployeePo::getSalary);
List<EmployeePo> pos = employeeDao.selectList(lqw);
四、逻辑条件的组合
逻辑条件的组合大体分为 2 种:
-
单纯的
...与...与...
/...或...或...
-
与或
混用,由于或
的优先级更高,因此可以改造成(... and ...) or (... and ...) or ...
这样的统一形式。
与与和或或
-
...与...与...
情况:如上例所示,QueryWrapper 的链式调用中,所表达的逻辑关系就是 and 的关系。
-
...或...或...
情况:这种关系中,在 Wrapper 对象的链式调用中穿插调用
or()
方法即可。or()
方法前后的条件就是或的关系。Wrapper<Employee> wp1 = new QueryWrapper<Employee>() .lt("salary", 1000) .or() .isNotNull("commission"); employeeDao.selectList(wp1).forEach(System.out::println);
与或混用
与或
混用的情况下,先要把你「心里」的 SQL 语句改造成通用形式:(... and ...) or (... and ...) or ...
。
Wrapper<Employee> wrapper = new QueryWrapper<Employee>()
.eq("department_id", 2L)
.lt("salary", 1500)
.or()
.eq("department_id", 3L)
.gt("salary", 1300);
employeeDao.selectList(wrapper).forEach(System.out::println);
五、条件为 null 的处理技巧
我们经常会遇到这样的场景:当查询条件值为非 null 时,就使用它作为查询条件;如果查询条件值为 null 时,就忽略这个条件。例如,当 department_id 有值时,就查询指定部门的员工信息,如果 department_id 值为 null ,那就忽略 department_id 条件,查询所有。
笨办法就是自己在拼接 Wrapper 查询条件时,加个 if 判断:
Long department_id = ...;
LambdaQueryWrapper<EmployeePo> lqw = new LambdaQueryWrapper<>();
if (department_id != null) {
lqw.eq(EmployeePo::getDepartmentId, department_id);
}
lqw.between(EmployeePo::getSalary, 500, 3000);
lqw.orderByDesc(EmployeePo::getSalary);
List<EmployeePo> pos = employeeDao.selectList(lqw);
对于这种情况,Mybatis Plus 提供了一个简单一点的写法:
Long department_id = ...;
LambdaQueryWrapper<EmployeePo> lqw = new LambdaQueryWrapper<>();
//下面这句
lqw.eq(department_id != null, EmployeePo::getDepartmentId, department_id);
lqw.between(EmployeePo::getSalary, 500, 3000);
lqw.orderByDesc(EmployeePo::getSalary);
List<EmployeePo> pos = employeeDao.selectList(lqw);
当判断条件(即,第一个参数)成立时,这个查询条件才存在。
六、设置查询列
之前的查询执行的都是 select *
查询所有列/字段,有时,我们需要指定查询特的那个字段。这种情况下就要调用 QueryWrapper 的 .select()
方法来指定带查询字段。
注意
对于没有指定的列/字段,查询结果 PO 类的对象中相应的属性值就是 null 。
-
LambdaQueryWrapper 的 select 用法
LambdaQueryWrapper<EmployeePo> lqw = new LambdaQueryWrapper<>(); lqw.select(EmployeePo::getId, EmployeePo::getName, EmployeePo::getSalary, EmployeePo::getCommission, EmployeePo::getDepartmentId); lqw.eq(EmployeePo::getDepartmentId, 2) .between(EmployeePo::getSalary, 500, 3000). orderByDesc(EmployeePo::getSalary); List<EmployeePo> pos = employeeDao.selectList(lqw);
-
QueryWrapper 的 select 用法
QueryWrapper<EmployeePo> lqw = new QueryWrapper<>(); lqw.select("id", "name", "salary", "commission", "department_id"); lqw.lambda().eq(EmployeePo::getDepartmentId, 2) .between(EmployeePo::getSalary, 500, 3000) .orderByDesc(EmployeePo::getSalary); List<EmployeePo> pos = employeeDao.selectList(lqw);
还是因为字符串容易“写错”,不好找 bug 的,建议使用 lambda 写法。
七、使用 SQL 聚合函数
在 Mybatis Plus 中使用聚合函数,类似于上面的指定特定列,使用 QueryWrapper 在 select 方法中指定聚合函数。例如:
QueryWrapper<EmployeePo> lqw = new QueryWrapper<>();
lqw.select("count(*) as total"); // 你还能起别名
但是接下来的 2 点就和上面的指定特定列有所不动了:
- 调用的是 mapper/dao 的
.selectMaps()
方法; - 这个方法的返回值是一个 map 的 list 。
qw.select("count(*) as total");
qw.lambda().between(EmployeePo::getSalary, 500, 3000);
List<Map<String, Object>> maps = employeeDao.selectMaps(qw);
maps.forEach(map -> System.out.println(map.get("total")));
为什么结果会是一个 map 的 list ?原因在于在你所执行的 SQL 语句的聚合函数可能不止一个,另外,结合分组,你所得到的聚合数据也不止一行。例如:
qw.select("count(*) as total", "avg(salary) as avgSalary", "avg(commission) as avgCommission");
qw.lambda().between(EmployeePo::getSalary, 500, 3000)
.groupBy(EmployeePo::getDepartmentId);
List<Map<String, Object>> maps = employeeDao.selectMaps(qw);
maps.forEach(map -> System.out.printf("%s %s %s\n",
map.get("total"),
map.get("avgSalary"),
map.get("avgCommission"))
);
八、模糊查询
Mybatis Plus 的 QueryWrapper 有一套专门的 like 方法用于模糊查询。如下:
LambdaQueryWrapper<EmployeePo> qw = new LambdaQueryWrapper<>();
qw.select(EmployeePo::getId, EmployeePo::getName, EmployeePo::getSalary);
qw.like(EmployeePo::getName, "A"); // like "%A%"
//qw.likeRight(EmployeePo::getName, "A"); // like "%A%"
//qw.likeLeft(EmployeePo::getName, "A"); // like "%A"
employeeDao.selectMaps(qw);
关于条件构造器 Wrapper 的更多使用,见官网
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)