【MyBatis Plus】Wrapper接口

一、核心定位:什么是 Wrapper?

Wrapper 是 MP 提供的条件构造器顶层接口,所有条件构造器都实现了这个接口。它的本质是:

  • 把 SQL 的 WHERE 条件(比如 username = ? AND status = 1)转换成 Java 代码的链式调用;
  • 最终 MP 会自动把 Wrapper 拼接成对应的 SQL 条件,无需手写 XML 条件判断。

二、常用实现类(重点记这 3 个)

Wrapper 是顶层接口,实际开发中不会直接用,而是用它的子类,核心有 3 个:

表格

实现类 核心特点 适用场景
QueryWrapper 通用查询条件构造器,支持所有 SQL 条件(=、>、<、LIKE、IN 等) 单表查询(最常用)
UpdateWrapper 专用更新条件构造器,支持 SET 字段赋值 + WHERE 条件 单表更新 / 删除
LambdaQueryWrapper 基于 Lambda 的查询构造器,字段名用「类::属性」,避免硬编码字段名(推荐) 所有单表查询(更优雅、无错)

2.1QueryWrapper:查询条件构造器

2.1.1方法

方法名 对应 SQL 语法 核心作用 典型使用场景
eq = 精准匹配某一字段等于指定值,是最基础、最常用的等值查询条件 查询用户名 ="admin"、状态 = 1、性别 ="男" 等精准条件
ne != 匹配某一字段不等于指定值,排除特定值的记录 查询状态≠0(排除禁用用户)、年龄≠18 等排除条件
gt > 匹配某一字段大于指定值,仅适用于数值 / 日期类型字段 查询年龄 > 18、创建时间 > 2024-01-01 等范围条件
lt < 匹配某一字段小于指定值,仅适用于数值 / 日期类型字段 查询年龄 < 60、金额 < 1000 等范围条件
like LIKE 模糊匹配字符串字段,默认拼接 %值%(包含匹配),可扩展 likeLeft/likeRight like 扩展: * likeLeft:拼接 值%(左匹配,如手机号以 138 开头); * likeRight:拼接 %值(右匹配,如邮箱以 @163.com结尾)。 查询用户名含 "张"、手机号以 "138" 开头等模糊查询
in IN 匹配某一字段值在指定的集合 / 多值范围内,替代多个 OR 拼接 查询 ID 在 [1,2,3]、状态在 [1,2] 等多值匹配条件
isNull IS NULL 匹配某一字段值为 null 的记录,对应反向方法 isNotNull(IS NOT NULL) 查询手机号为空、邮箱未填写等空值判断条件

2.1.2方法举例

1. eq(字段=值 匹配)
复制代码
/**
 * 需求:查询用户名等于"admin"的用户
 * 对应SQL:SELECT * FROM sys_user WHERE username = 'admin'
 */
public List<SysUser> testEq() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(SysUser::getUsername, "admin"); // 字段=值
    return sysUserMapper.selectList(wrapper);
}
2. ne(!= 不等值匹配)
复制代码
/**
 * 需求:查询状态不等于0(未禁用)的用户
 * 对应SQL:SELECT * FROM sys_user WHERE status != 0
 */
public List<SysUser> testNe() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.ne(SysUser::getStatus, 0); // 字段!=值
    return sysUserMapper.selectList(wrapper);
}
3. gt(> 大于)
复制代码
/**
 * 需求:查询年龄大于18的用户
 * 对应SQL:SELECT * FROM sys_user WHERE age > 18
 */
public List<SysUser> testGt() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.gt(SysUser::getAge, 18); // 字段>值
    return sysUserMapper.selectList(wrapper);
}
4. lt(< 小于)
复制代码
/**
 * 需求:查询年龄小于60的用户
 * 对应SQL:SELECT * FROM sys_user WHERE age < 60
 */
public List<SysUser> testLt() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.lt(SysUser::getAge, 60); // 字段<值
    return sysUserMapper.selectList(wrapper);
}
5. like(模糊匹配)
复制代码
/**
 * 需求1:查询用户名包含"张"的用户(默认%值%)
 * 对应SQL:SELECT * FROM sys_user WHERE username LIKE '%张%'
 * 扩展:likeLeft(值%)= 以"张"开头;likeRight(%值)= 以"张"结尾
 */
public List<SysUser> testLike() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.like(SysUser::getUsername, "张"); // 模糊匹配包含"张"
    // wrapper.likeLeft(SysUser::getPhone, "138"); // 手机号以138开头
    return sysUserMapper.selectList(wrapper);
}
6. in(IN 多值匹配)
复制代码
/**
 * 需求:查询ID在1、2、3范围内的用户
 * 对应SQL:SELECT * FROM sys_user WHERE id IN (1,2,3)
 */
public List<SysUser> testIn() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    // 方式1:传集合
    List<Long> ids = Arrays.asList(1L, 2L, 3L);
    wrapper.in(SysUser::getId, ids);
    // 方式2:直接传多个值
    // wrapper.in(SysUser::getStatus, 1, 2); // 状态在1、2范围内
    return sysUserMapper.selectList(wrapper);
}
7. isNull(IS NULL 空值匹配)
复制代码
/**
 * 需求:查询手机号为空的用户
 * 对应SQL:SELECT * FROM sys_user WHERE phone IS NULL
 * 扩展:isNotNull = phone IS NOT NULL(手机号不为空)
 */
public List<SysUser> testIsNull() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.isNull(SysUser::getPhone); // 字段为null
    // wrapper.isNotNull(SysUser::getPhone); // 字段不为null
    return sysUserMapper.selectList(wrapper);
}
8.orderByDesc() - 按照字段名降序
9.orderByASC() - 按照字段名升序
扩展:多条件组合示例(实战高频)
复制代码
/**
 * 需求:查询年龄>18 且 状态=1 且 用户名含"张"的用户
 * 对应SQL:SELECT * FROM sys_user WHERE age > 18 AND status = 1 AND username LIKE '%张%'
 */
public List<SysUser> testMultiCondition() {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.gt(SysUser::getAge, 18)
           .eq(SysUser::getStatus, 1)
           .like(SysUser::getUsername, "张");
    return sysUserMapper.selectList(wrapper);
}

2.1.3 中间以and连接

2.2UpdateWrapper类

2.2.0核心优势

官方明确其核心优势是支持将字段值设为 null(区别于 "实体 + QueryWrapper" 的更新方式)。

2.2.1核心方法

方法 作用 示例
set() 拼接 SET 子句,指定要更新的字段和值 set("password", "123456")
条件方法 拼接 WHERE 子句(和 QueryWrapper 一致) eq("username", "admin")in("id", 1,2)

entity=null : 指的是本次更新操作完全由UpdateWrapper来指定更新的字段和值,不使用entity中的任何属性。

bash 复制代码
@Test
    public void testUpdateWithWrapper(){
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.set("tiger_name", "王虎-更新");
        updateWrapper.eq("tiger_age", 8);
        tigerMapper.update(null, updateWrapper);//entity = null 指的是:本次更新操作完全由 UpdateWrapper 来指定要更新的字段和值,不使用实体类 entity 中的任何属性。
        System.out.println("更新成功!");
    }

2.2.2拼接方法

2.3LambdaWrapper

2.3.0修改的地方

Lambda 系列 Wrapper 是官方为解决 "硬编码字段名" 问题设计的增强版,基于 Lambda 表达式引用实体类属性,支持编译期字段校验(字段名拼写错误直接编译失败),是生产环境首选。

2.3.1LambdaQueryWrapper :Lambda 风格查询构造器

bash 复制代码
@Autowired
private TigerMapper tigerMapper;

// 1. 方式1:直接new实例(类型安全,无硬编码)
LambdaQueryWrapper<Tiger> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 拼接条件:tiger_age = 5 AND tiger_name LIKE '%虎%'(引用实体属性,IDE自动补全)
lambdaQueryWrapper.eq(Tiger::getTigerAge, 5)
                  .like(Tiger::getTigerName, "虎")
                  .gt(Tiger::getTigerSalary, 500);

// 2. 方式2:Wrappers工具类(官方推荐,简化代码)
LambdaQueryWrapper<Tiger> lambdaQueryWrapper2 = Wrappers.lambdaQuery();
lambdaQueryWrapper2.ne(Tiger::getTigerAge, 3)
                  .isNotNull(Tiger::getTigerSalary)
                  .orderByDesc(Tiger::getTigerAge);

// 3. 执行查询(与普通Wrapper调用方式一致)
List<Tiger> tigerList = tigerMapper.selectList(lambdaQueryWrapper);

2.3.2LambdaUpdateWrapper :Lambda 风格更新构造器

bash 复制代码
@Autowired
private TigerMapper tigerMapper;

// 1. 方式1:直接new实例(无硬编码字段名)
LambdaUpdateWrapper<Tiger> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
// 拼接更新逻辑:SET tiger_name = 'Lambda虎', tiger_salary = 600 WHERE tiger_id = 1
lambdaUpdateWrapper.set(Tiger::getTigerName, "Lambda虎")
                   .set(Tiger::getTigerSalary, 600.00)
                   .eq(Tiger::getTigerId, 1);

// 2. 方式2:Wrappers工具类(官方推荐)
LambdaUpdateWrapper<Tiger> lambdaUpdateWrapper2 = Wrappers.lambdaUpdate();
// 拼接更新逻辑:SET tiger_age = tiger_age + 1 WHERE tiger_name = '李虎'
lambdaUpdateWrapper2.setSql("tiger_age = tiger_age + 1") // 支持原生SQL片段
                   .eq(Tiger::getTigerName, "李虎");

// 3. 执行更新
int affectedRows = tigerMapper.update(null, lambdaUpdateWrapper);

2.3.3支持setSql的原生SQL语句

bash 复制代码
lambdaUpdateWrapper2.setSql("tiger_age = tiger_age + 1") // 支持原生SQL片段
                   .eq(Tiger::getTigerName, "李虎"); 

2.4普通Wrapper和LambdaWrapper的对比

| 字段引用方式 | 优缺点 | 适用场景 |
|-------------------|---------------------------------------|---------------------|-------------|
| 普通 Wrapper | 数据库字段名字符串(如 "tiger_name") | 灵活但易拼写错误,运行时暴露问题 | 快速测试、简单场景 |
| Lambda 系列 Wrapper | 实体属性 Lambda 引用(如 Tiger::getTigerName) | 类型安全、编译期校验,官方推荐生产使用 | 生产环境、复杂业务场景 |

三、实战用法(结合你的用户登录 / 查询场景)

以你熟悉的 SysUser 表为例,演示 3 种常用写法:

1. 基础用法:QueryWrapper(硬编码字段名)

复制代码
// 需求:查询 用户名=admin 且 状态=1 的用户
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private SysUserMapper userMapper;

    @Override
    public SysUser findUser(String username) {
        // 1. 创建查询构造器
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        // 2. 链式拼接条件(等价于 WHERE username = ? AND status = 1)
        wrapper.eq("username", username)  // eq = equal,等于
               .eq("status", 1);         // 多条件默认用 AND 连接
        // 3. 调用 MP 通用方法,传入 wrapper
        return userMapper.selectOne(wrapper);
    }
}

2. 推荐用法:LambdaQueryWrapper(避免字段名硬编码)

复制代码
@Override
public SysUser findUser(String username) {
    // Lambda 方式:字段名用 SysUser::getUsername,编译期校验,不会拼错
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(SysUser::getUsername, username)
           .eq(SysUser::getStatus, 1);
    return userMapper.selectOne(wrapper);
}

✅ 优势:如果数据库字段名改了(比如 usernameuser_name),只要实体类属性名没改,代码不用动;硬编码写法会直接报错。

3. 更新用法:UpdateWrapper

复制代码
// 需求:把 admin 用户的密码改成 123456,且状态=1
@Override
public boolean updateUserPassword(String username) {
    UpdateWrapper<SysUser> wrapper = new UpdateWrapper<>();
    // SET 子句:设置要更新的字段
    wrapper.set("password", "123456")
           // WHERE 子句:更新条件
           .eq("username", username)
           .eq("status", 1);
    // 调用 MP 通用更新方法
    return userMapper.update(null, wrapper) > 0;
}

四、核心优势(对比传统 MyBatis)

表格

传统 MyBatis(XML) MyBatis Plus(Wrapper)
手写 <if>/<where> 标签 一行链式调用搞定,无需 XML
字段名硬编码(易拼错) Lambda 方式编译期校验(字段名不会错)
动态条件需写大量 XML 动态条件用 if 包裹链式调用即可
多表联查需手写 SQL 单表查询极致简洁,多表联查仍需手写 SQL

五、常用条件方法(速查)

表格

Wrapper 方法 SQL 等价条件 示例
eq = eq("username", "admin")
ne != ne("status", 0)
gt > gt("age", 18)
like LIKE like("username", "%admin%")
in IN in("id", 1,2,3)
and AND 多条件默认 AND
or OR or().eq("status", 2)

总结

  1. Wrapper 是 MP 条件构造器的顶层接口,核心子类是 QueryWrapper/LambdaQueryWrapper/UpdateWrapper
  2. 优先用 LambdaQueryWrapper:避免字段名硬编码,编译期校验,最优雅;
  3. 核心价值:用 Java 代码链式拼接 SQL 条件,替代 XML 中的 <if>/<where>,简化单表条件查询 / 更新。
相关推荐
nudt_qxx2 小时前
Ubuntu 26.04 LTS“坚毅浣熊”(Resolute Raccoon) 新特性前瞻
linux·数据库·ubuntu
tianzhiyi1989sq2 小时前
C++工具库之PugiXML使用指南
java·数据库·c++
毕设源码-钟学长2 小时前
【开题答辩全过程】以 哈尔滨市小酒窝APP为例,包含答辩的问题和答案
java
游乐码2 小时前
c#运算符重载
开发语言·c#
人道领域2 小时前
MyBatisPlus高效开发实战指南
java·开发语言·数据库
游乐码2 小时前
c#继承的原则
开发语言·c#
lsx2024062 小时前
Servlet 文件上传
开发语言
游乐码2 小时前
c#内部类和分部类
开发语言·c#
消失的旧时光-19432 小时前
C++ 多线程与并发系统取向(四)—— std::condition_variable:线程协作与生产者消费者模型(类比 Java wait/notify)
开发语言·c++