MyBatisPlus条件构造器

2024/1/14 MyBatisPlus框架

在前面章节中,我们用到了不少条件构造器,本章介绍下MyBatisPlus中提供的条件构造器有哪些。

# 1、条件构造器关系

类关系图

  • AbstractWrapper是QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类。
  • 常用:QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper)

# 2、AbstractWrapper

  • AbstractWrapper为条件构造器的抽象类,它提供很多条件方法。
  • AbstractWrapper是QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类。
  • 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
  • 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

# 2.1、使用案例

@Test
public void testQuery9(){
    // 查询id小于20
    List<StudentPO> list = studentService.list(new LambdaQueryWrapper<StudentPO>().le(StudentPO::getId, 20));
    log.info("list========>"+list);
}
1
2
3
4
5
6

# 2.2、AbstractWrapper方法

方法名 描述 案例说明
allEq 查询字段值全部相等的记录。 allEq案例
eq 查询字段值等于给定值的记录。 eq("name", "老王")--->name = '老王'
ne 查询字段值不等于给定值的记录。 ne("name", "老王")--->name <> '老王'
gt 查询字段值大于给定值的记录。 gt("age", 18)--->age > 18
ge 查询字段值大于等于给定值的记录。 ge("age", 18)--->age >= 18
lt 查询字段值小于给定值的记录。 lt("age", 18)--->age < 18
le 查询字段值小于等于给定值的记录。 le("age", 18)--->age <= 18
between 查询字段值在两个值之间的记录。 between("age", 18, 30)--->age between 18 and 30
notBetween 查询字段值不在两个值之间的记录。 notBetween("age", 18, 30)--->age not between 18 and 30
like 查询字段值包含给定值的记录。 like("name", "王")--->name like '%王%'
notLike 查询字段值不包含给定值的记录。 notLike("name", "王")--->name not like '%王%'
likeLeft 查询字段值以给定值开头的记录。 likeLeft("name", "王")--->name like '%王'
likeRight 查询字段值以给定值结尾的记录。 likeRight("name", "王")--->name like '王%'
notLikeLeft 查询字段值不以给定值开头的记录。 notLikeLeft("name", "王")--->name not like '%王'
notLikeRight 查询字段值不以给定值结尾的记录。 notLikeRight("name", "王")--->name not like '王%'
isNull 查询字段值为null的记录。 isNull("name")--->name is null
isNotNull 查询字段值不为null的记录。 isNotNull("name")--->name is not null
in 查询字段值在给定集合中的记录。 例1: in("age",{1,2,3})--->age in (1,2,3)
例2: in("age", 1, 2, 3)--->age in (1,2,3)
notIn 查询字段值不在给定集合中的记录。 例1: notIn("age",{1,2,3})--->age not in (1,2,3)
例2: notIn("age", 1, 2, 3)--->age not in (1,2,3)
inSql 生成SQL中的IN子句,用于查询。注意:这可能会增加SQL注入的风险,应谨慎使用。 例1: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
例2: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
notInSql 生成SQL中的NOT IN子句,用于查询。同样,注意SQL注入的风险。 例1: notInSql("age", "1,2,3,4,5,6")--->age not in (1,2,3,4,5,6)
例2: notInSql("id", "select id from table where id < 3")--->id not in (select id from table where id < 3)
groupBy 指定SQL的GROUP BY子句。 groupBy("id", "name")--->group by id,name
orderByAsc 指定SQL的ORDER BY子句,升序排列。 orderByAsc("id", "name")--->order by id ASC,name ASC
orderByDesc 指定SQL的ORDER BY子句,降序排列。 rderByDesc("id", "name")--->order by id DESC,name DESC
orderBy 指定SQL的ORDER BY子句,可指定排序方式。 orderBy(true, true, "id", "name")--->order by id ASC,name ASC
having 指定SQL的HAVING子句,通常与GROUP BY配合使用。 例1: having("sum(age) > 10")--->having sum(age) > 10
例2: having("sum(age) > {0}", 11)--->having sum(age) > 11
func 调用数据库函数或方法。 func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
or 表示SQL中的OR逻辑操作。 例1: eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'
例2: or(i -> i.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着')
and 表示SQL中的AND逻辑操作。 and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')
nested 表示嵌套条件,常用于构建复杂的查询条件。 nested(i -> i.eq("name", "李白").ne("status", "活着"))--->(name = '李白' and status <> '活着')
apply 用于构建SQL的动态WHERE子句,更灵活地拼接条件。 apply案例
last 用于手动拼接SQL片段,通常在链式调用中结束时使用。 last案例
exists 表示子查询存在时返回true,常用于EXISTS条件。 exists("select id from table where age = 1")--->exists (select id from table where age = 1)
notExists 表示子查询不存在时返回true,常用于NOT EXISTS条件。 notExists("select id from table where age = 1")--->not exists (select id from table where age = 1)

# 2.3、✨案例说明

# allEq案例

全部eq(或个别isNull)

个别参数说明:

  • params : key为数据库字段名,value为字段值
  • null2IsNull : 为true则在map的value为null时调用 isNull 方法,为false时则忽略value为null的
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 
1
2
3

  • 例1: allEq({id:1,name:"老王",age:null})--->id = 1 and name = '老王' and age is null
  • 例2: allEq({id:1,name:"老王",age:null}, false)--->id = 1 and name = '老王'

个别参数说明:

  • filter : 过滤函数,是否允许字段传入比对条件中
  • params 与 null2IsNull : 同上

  • 例1: allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null})--->name = '老王' and age is null
  • 例2: allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null}, false)--->name = '老王'

# apply案例

拼接 sql

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
1
2

注意事项

该方法可用于数据库函数 动态入参的params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!

  • 例: apply("id = 1")--->id = 1
  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

# last案例

无视优化规则直接拼接到 sql 的最后

last(String lastSql)
last(boolean condition, String lastSql)
1
2

注意事项

只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

例: last("limit 1")

# 3、QueryWrapper

说明

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件,及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取

QueryWrapper 除了 AbstractWrapper中的方法,还提供了一个select的方法:

select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
1
2
3

案例

  • 例: select("id", "name", "age")
  • 例: select(i -> i.getProperty().startsWith("test"))
@SpringBootTest
@Slf4j
public class TestController {

    @Autowired
    private StudentServiceImpl studentService;

    @Test
    public void testQuery(){
        // 只查询 id 和 name 字段
        Wrapper<StudentPO> wrapper = new QueryWrapper<StudentPO>().select("id", "name")).eq("name", "ls");
        List<StudentPO> list = studentService.list(wrapper);
        log.info("studentList========>"+list);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4、UpdateWrapper

说明

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件,及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

UpdateWrapper 除了 AbstractWrapper 中的方法,还提供了一个其他几个方法:

# 4.1、set

set(String column, Object val)
set(boolean condition, String column, Object val)
1
2

案例

  • 例: set("name", "老李头")
  • 例: set("name", "")--->数据库字段值变为空字符串
  • 例: set("name", null)--->数据库字段值变为null
@Test
public void tesUpdate(){
    Wrapper<StudentPO> wrapper = new UpdateWrapper<StudentPO>().set("name","ss");
    StudentPO studentPO = new StudentPO();
    studentPO.setName("kk");

    studentService.update(studentPO,wrapper);
}

1
2
3
4
5
6
7
8
9

# 4.2、setSql

setSql(String sql)
1

  • 设置 SET 部分 SQL
  • 例: setSql("name = '老李头'")

# 4.3、lambda

获取 LambdaWrapper

  • 在QueryWrapper中是获取LambdaQueryWrapper
  • 在UpdateWrapper中是获取LambdaUpdateWrapper
LambdaQueryWrapper<StudentPO> lambda1 = new QueryWrapper<StudentPO>().lambda();
LambdaUpdateWrapper<StudentPO> lambda2 = new UpdateWrapper<StudentPO>().lambda();
1
2

# 5、使用 Wrapper 自定义SQL

# 5.1、注解方式

需要mybatis-plus版本 >= 3.0.7 param 参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER) 使用${ew.customSqlSegment} 不支持 Wrapper 内的entity生成where语句

// StudentMapper中增加方法
@Select("select * from student ${ew.customSqlSegment}")
List<StudentPO> selectAllStudent(@Param(Constants.WRAPPER) Wrapper wrapper);


// 测试
@Test
public void testQuery10(){
    List<StudentPO> list = studentMapper.selectAllStudent(new LambdaQueryWrapper<StudentPO>().eq(StudentPO::getName, "ls"));
    log.info("list========>"+list);
}

// 执行SQL:select * from student WHERE (name = 'ls')
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.2、XML方式

StudentMapper中增加方法

List<StudentPO> selectAllStudent(Wrapper wrapper);
1

在Mapper.xml中使用

<select id="selectAllStudent" resultType="StudentPO">
	SELECT * FROM student ${ew.customSqlSegment}
</select>
1
2
3

结果和注解方式一样