前言:
上章节我们讲解了MyBatis-Plus自动SQL注入原理以及简单了解了什么是条件构造器。本章节就来对条件构造器的各个方法的使用进行讲解。
一、性能分析插件
在条件构造器使用之前,我们先讲解下MyBatis-Plus提供的一个扩展插件-性能分析插件。可以用于输出每条 SQL 语句及其执行时间。之所以先讲解它呢,是因为接下来,我们讲解条件构造器的各个方法,只查看和比较SQL的输出打印,不做执行后数据结果的查看。
1、配置
在前面章节介绍配置问题1时,其中一种解决方法是新建一个配置类。现在配置插件,我们可以在这个类中添加如下代码,在Spring Boot启动时实例化插件类对象,加载到容器中:
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
参数说明:
- 参数:maxTime SQL 执行最大时长,超过自动停止运行,有助于发现问题。
- 参数:format SQL SQL是否格式化,默认false。这里设置为true,格式化打印转出。
- 该插件只用于开发环境,不建议生产环境使用。
二、条件构造器使用
官方警告:不支持以及不赞成在RPC调用中把 Wrapper 进行传输。wrapper 很重,传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)。正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作 。
1、QueryWrapper
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件。这里使用的是数据库字段,不是Java属性。经下面讲解提供条件方法
-
allEq 多个EQ或个别isNull
接口与默认方法:
default <V> Children allEq(Map<R, V> params) {
return this.allEq(params, true);
}
default <V> Children allEq(Map<R, V> params, boolean null2IsNull) {
return this.allEq(true, params, null2IsNull);
}
<V> Children allEq(boolean condition, Map<R, V> params, boolean null2IsNull);
default <V> Children allEq(BiPredicate<R, V> filter, Map<R, V> params) {
return this.allEq(filter, params, true);
}
default <V> Children allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) {
return this.allEq(true, filter, params, null2IsNull);
}
<V> Children allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull);
参数说明:
- params:字段名与字段值的键值对,
key
为数据库字段名,value
为字段值 - condition:该条件是否加入生成的sql中
- null2IsNull: 为
true
则在map
的value
为null
时调用 isNull 方法,为false
时则忽略value
为null
的 - filter:过滤params中的键值加入生成的sql中
实例:
@Test
public void contextLoads() {
QueryWrapper<SysLog> queryWrapper = new QueryWrapper();
Map<String, Object> map = new HashMap<>();
map.put("f_option_type", "1");
map.put("f_option_person", "admin");
queryWrapper.allEq(map);
sysLogMapper.selectList(queryWrapper);
}
Time:53 ms - ID:com.banxun.demo.mapper.SysLogMapper.selectList
Execute SQL:
SELECT
f_log_id AS logId,
f_option_type AS optionType,
f_option_person AS optionPerson,
f_option_content AS optionContent,
f_option_ip AS optionIp,
f_option_type AS optionStatus,
f_error_info AS errorInfo,
f_option_time AS optionTime
FROM
t_sys_log
WHERE
f_option_person = 'admin'
AND f_option_type = '1'
可以看到,在map中传入了两个值对。控台打印了执行时间以及执行的SQL,在where 条件后拼接了f_option_person = 'admin' AND f_option_type = '1'
我们给map中键f_option_person的value设为空,再看下结果
@Test
public void contextLoads() {
QueryWrapper<SysLog> queryWrapper = new QueryWrapper();
Map<String, Object> map = new HashMap<>();
map.put("f_option_type", "1");
map.put("f_option_person", null);
queryWrapper.allEq(map);
sysLogMapper.selectList(queryWrapper);
}
Time:25 ms - ID:com.banxun.demo.mapper.SysLogMapper.selectList
Execute SQL:
SELECT
f_log_id AS logId,
f_option_type AS optionType,
f_option_person AS optionPerson,
f_option_content AS optionContent,
f_option_ip AS optionIp,
f_option_type AS optionStatus,
f_error_info AS errorInfo,
f_option_time AS optionTime
FROM
t_sys_log
WHERE
f_option_person IS NULL
AND f_option_type = '1'
可以看到,当键f_option_person值为空,默认会在where 条件后拼接了f_option_person IS NULL ,可以看null2IsNull 默认是true,现在传false,看下执行结果
@Test
public void contextLoads() {
QueryWrapper<SysLog> queryWrapper = new QueryWrapper();
Map<String, Object> map = new HashMap<>();
map.put("f_option_type", "1");
map.put("f_option_person", null);
queryWrapper.allEq(map, false);
sysLogMapper.selectList(queryWrapper);
}
Time:25 ms - ID:com.banxun.demo.mapper.SysLogMapper.selectList
Execute SQL:
SELECT
f_log_id AS logId,
f_option_type AS optionType,
f_option_person AS optionPerson,
f_option_content AS optionContent,
f_option_ip AS optionIp,
f_option_type AS optionStatus,
f_error_info AS errorInfo,
f_option_time AS optionTime
FROM
t_sys_log
WHERE
f_option_type = '1'
输出的SQL可以看到,传null2IsNull为false,where后不执行 is null。我们再来看filter参数的用法。filter是BiPredicate函数接口类型,返回Boolean。这里使用时需要先了解JDK8新特性-函数接口使用方式。这里不做深入讲解,我们使用null2IsNull默认true。如果没有传filter,应该两个条件都打印,现在来看下执行结果
@Test
public void contextLoads() {
QueryWrapper<SysLog> queryWrapper = new QueryWrapper();
Map<String, Object> map = new HashMap<>();