二、MybatisPlus-进阶使用-条件构造器

405 阅读5分钟

本文是系列文章,目录:
本文是系列文章,目录:
一、MybatisPlus-基本使用
二、MybatisPlus-进阶使用-条件构造器
三、MybatisPlus-进阶使用-自定义sql
四、MybatisPlus-进阶使用-Service接口(1)-基本使用
五、MybatisPlus-进阶使用-Service接口(2)-自定义service
六、MybatisPlus-进阶使用-Service接口(3)- 批量新增
七、MybatisPlus-进阶使用-逻辑删除
八、MybatisPlus-进阶使用-枚举处理器
九、MybatisPlus-进阶使用-JSON类型处理器
十、MybatisPlus-进阶使用-配置文件加密
十一、MybatisPlus-插件功能-分页插件(1)
十二、MybatisPlus-插件功能-分页插件(2)-通用分页封装
十三、MybatisPlus-插件功能-乐观锁插件
十四、MybatisPlus-插件功能-sql性能分析
十五、MybatisPlus-自动填充字段
MybatisPlus-问题汇总

一、简介

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。

MyBatis-Plus 的 Wrapper 类是构建复杂查询和更新条件的关键工具。它允许开发者以链式调用的方式构造 SQL 的 WHERE 子句,提供了极大的灵活性和便利性。

需要注意的是:QueryWrapper UpdateWrapper 字段部分,如有允许 前端传入 SQL 片段 这可能会导致 SQL 注入风险 需要校验,更多查看 预防安全漏洞

二、条件构造器(Wrapper)

在 MyBatis-Plus 中,Wrapper 类是构建查询和更新条件的核心工具。以下是主要的 Wrapper 类及其功能:

  • AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
  • QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 and 和 or 逻辑。
  • UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

继承图 微信图片_20240813184834.png Wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法:

image.png

QueryWrapperAbstractWrapper的基础上拓展了一个select方法,允许指定查询字段:

image.png
UpdateWrapperAbstractWrapper的基础上拓展了一个set方法,允许指定SQL中的SET部分:

image.png

三、使用QueryWrapper

无论是修改、删除、查询,都可以使用QueryWrapper来构建查询条件。接下来看一些例子:
查询:查询出名字中带o的,存款大于等于1000元的人。代码如下:

package com.pino.demo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pino.demo.domain.po.User;
import com.pino.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class QueryWrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void testQueryWrapper() {
       // 查询:查询出名字中带o的,存款大于等于1000元的人
       // 1.构建查询条件 where name like "%o%" AND balance >= 1000
       QueryWrapper<User> wrapper = new QueryWrapper<User>()
             .select("id", "username", "info", "balance")
             .like("username", "o")
             .ge("balance", 1000);
       // 2.查询数据
       List<User> users = userMapper.selectList(wrapper);
       users.forEach(System.out::println);
       // 3.使用 user + wrapper 修改用户信息
       User user = new User();
       user.setBalance(2000);
       userMapper.update(user, wrapper);
    }
}

四、使用UpdateWrapper

基于BaseMapper中的update方法更新时只能直接赋值,对于一些复杂的需求就难以实现。
例如:更新id为1,2,4的用户的余额,扣200,对应的SQL应该是:

UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)

SET的赋值结果是基于字段现有值的,这个时候就要利用UpdateWrapper中的setSql功能了:

package com.pino.demo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.pino.demo.domain.po.User;
import com.pino.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class UpdateWrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void testUpdateWrapper() {
       // 更新id为1,2,4的用户的余额,扣200,对应的SQL应该是:
       // 1.ids
       List<Long> ids = List.of(1L, 2L, 4L);
       // 2.生成sql
       UpdateWrapper<User> wrapper = new UpdateWrapper<>();
       wrapper.in("id", ids)
             .setSql("balance = balance - 200");
       // 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,而是基于UpdateWrapper中的setSQL来更新
       userMapper.update(null, wrapper);
    }
}

五、LambdaQueryWrapper和LambdaUpdateWrapper

LambdaQueryWrapperLambdaUpdateWrapper是基于Lambda 表达式的条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。

package com.pino.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.pino.demo.domain.po.User;
import com.pino.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/***
 * 这里是对 LambdaQueryWrapper 和 LambdaUpdateWrapper的测试
 */
@SpringBootTest
public class LambdaWrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void testLambdaQueryWrapper() {
       // 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000
       LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
       wrapper
             .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
             .like(User::getUsername, "o")
             .ge(User::getBalance, 1000);
       // 2.查询
       List<User> users = userMapper.selectList(wrapper);
       users.forEach(System.out::println);
    }
    @Test
    void testLambdaUpdateWrapper() {
       // 1.构建条件 WHERE id = 1
       List<Long> ids = List.of(1L, 2L, 4L);
       LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
       wrapper.in(User::getId, ids).setSql("balance = balance - 200");


       // 2.查询
       int updateResult = userMapper.update(null, wrapper);
       System.out.println(updateResult);
    }
}