学习要求
良好的java基础, 熟悉SpringBoot框架,熟悉Mybatis框架
教程目标
了解并掌握MyBatis-Plus条件构造器
视频教程
概念
条件构造器-Wrapper按照官方的给出的解释是用于生成 sql 的 where 条件,但在使用的过程发现Wrapper不仅仅只是生产where条件,准确的来说,wrapper更新mybatis中的<sql></sql>动态标签,可以拼接where 条件也可拼接set 语法,同样也可以拼接 select 列列表等。
类体系结构
按功能分
修改型:UpdateWrapper LambdaUpdateWrapper
查询型:QueryWrapper LambdaQueryWrapper
按操作分
传统型:QueryWrapper UpdateWrapper
Lambda:LambdaQueryWrapper LambdaUpdateWrapper
不管怎么分,它们都有一个共同的父类:AbstractWrapper, 父类里面定义wrapper核心的条件方法比如:
allEqeq ne gt ge lt le between notBetween like notLike likeLeft likeRight isNull isNotNull in notIn inSql notInSql groupBy orderByAsc orderByDesc orderBy having func or and nested apply last exists notExists 等
Update类型的Wrapper独有操作方法:set setSql
Query类型的Wrapper独有操作方法:select
UpdateWrapper 与 LambdaUpdateWrapper
这2个Wrapper都是用于对数据修改的条件构造器
需求:将id=1的员工name修改为zhangsanfeng
UpdateWrapper
@Test
public void testUpdate(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 1L);
wrapper.set("name", "zhangsanfeng");
employeeMapper.update(null, wrapper);
}
LambdaUpdateWrapper
@Test
public void testUpdateLambda(){
LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(Employee::getId, 1L);
wrapper.set(Employee::getName, "zhangsanfeng");
employeeMapper.update(null, wrapper);
}
LambdaUpdateWrapper 的update 跟 UpdateWrapper 的update操作一样,唯一区别点在于UpdateWrapper的操作列都是以字符串的形式存在,LambdaUpdateWrapper 的操作列使用lambda表达式。查看源码,你发现:Employee::getName其实最终会解析name属性来。简单的理解就是通过Employee类中的getName方法,将name属性解析出来。这么折腾好处是比直接写字符串方式多了一种操作前检查(避免出现手误)
@Override
public LambdaUpdateWrapper<T> set(boolean condition, SFunction<T, ?> column, Object val) {
if (condition) {
sqlSet.add(String.format("%s=%s", columnToString(column), formatSql("{0}", val)));
}
return typedThis;
}
protected String columnToString(SFunction<T, ?> column, boolean onlyColumn) {
return getColumn(LambdaUtils.resolve(column), onlyColumn);
}
private String getColumn(SerializedLambda lambda, boolean onlyColumn) {
Class<?> aClass = lambda.getInstantiatedType();
tryInitCache(aClass);
String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
ColumnCache columnCache = getColumnCache(fieldName, aClass);
return onlyColumn ? columnCache.getColumn() : columnCache.getColumnSelect();
}
独有方法操作
需求1其实还是一种写法,使用到:setSql
@Test
public void testUpdate(){
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 1L);
//wrapper.set("name", "zhangsanfeng");
wrapper.setSql("name='zhangsanfeng'");
employeeMapper.update(null, wrapper);
}
setSql表示使用拼接SQL片段方式进行操作,区别从打印的SQL可以看出
set方式:
SQL:
UPDATE employee SET name=? WHERE (id = ?)
参数:
zhangsanfeng(String), 1(Long)
setSql方式:
SQL:
UPDATE employee SET name='zhangsanfeng' WHERE (id = ?)
参数:
1(Long)
2个对比,可以很明显看出set方式使用预编译操作方法,而setSql 直接进行拼接,所以操作上更推荐set方式。
QueryWrapper 与 LambdaQueryWrapper
需求:查询name=zhangsan, age=18 的员工信息
QueryWrapper
@Test
public void testQuery(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name", "zhangsan");
wrapper.eq("age", 18);
List<Employee> list = employeeMapper.selectList(wrapper);
}
LambdaQueryWrapper
@Test
public void testQueryLambda(){
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Employee::getName, "zhangsan");
wrapper.eq(Employee::getAge, 18);
List<Employee> list = employeeMapper.selectList(wrapper);
}
2个Wrapper操作跟上面update操作一个样,都是将字符串的操作列转换成lambda方式,其实没有本质上的区别。
独有方法操作
query类型wrapper也有自己的独有的方法:select
@Test
public void testQuery(){
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select("id", "name");
wrapper.eq("name", "zhangsan");
wrapper.eq("age", 18);
List<Employee> list = employeeMapper.selectList(wrapper);
}
里面的wrapper.select("id", "name"); 方法表示查询结果返回id,name 2列,等价于:
SELECT id,name FROM employee WHERE (name = ? AND age = ?)
如果不加select 方法,默认查询所有列,等价于:
SELECT * FROM employee WHERE (name = ? AND age = ?)
Wrapper实例构建方式
@Test
public void testWrapper(){
//wrapper对象的创建
//query
QueryWrapper<Employee> queryWrapper1 = new QueryWrapper<>();
QueryWrapper<Employee> queryWrapper2 = Wrappers.<Employee>query();
LambdaQueryWrapper<Employee> queryWrapper3 = new LambdaQueryWrapper<>();
LambdaQueryWrapper<Employee> queryWrapper4 = Wrappers.<Employee>lambdaQuery();
LambdaQueryWrapper<Employee> queryWrapper5 = queryWrapper1.lambda();
//update
UpdateWrapper<Employee> updateWrapper1 = new UpdateWrapper<>();
UpdateWrapper<Employee> updateWrapper2 = Wrappers.<Employee>update();
LambdaUpdateWrapper<Employee> updateWrapper3 = new LambdaUpdateWrapper<>();
LambdaUpdateWrapper<Employee> updateWrapper4 = Wrappers.<Employee>lambdaUpdate();
LambdaUpdateWrapper<Employee> updateWrapper5 = updateWrapper1.lambda();
}
其中的Wrappers 是mybatis-plus官方提供的构建Wrapper实例的工具类。
传统Wrapper与LambadWrapper选择
单从可读性来看,建议使用传统的Wrapper,从预防手误来看,建议使用LambadWrapper
实际开发以公司规定为准则。