MyBatis-Plus 学习:Wrapper 查询与条件构造器
MyBatis-Plus 入门项目,演示 BaseMapper、QueryWrapper 条件查询、LambdaQueryWrapper 和自定义方法。
MyBatis-Plus:Wrapper 查询与条件构造器实战
为什么用 MyBatis-Plus
MyBatis 本身已经很轻量,但日常使用中重复的 CRUD SQL 代码太多——每个表都要写 insert、selectById、updateById、deleteById。MyBatis-Plus 通过代码生成器 + BaseMapper 解决了这个问题,把开发者从模板代码中解放出来。
BaseMapper 完整 CRUD
不用写任何 SQL 就是 MyBatis-Plus 最大的卖点:
// 继承 BaseMapper 后,自动获得以下方法
public interface UserMapper extends BaseMapper<User> {
// 无需写任何代码
}
// 使用
userMapper.selectById(1L); // 按 ID 查
userMapper.selectList(null); // 查全部
userMapper.selectPage(page, wrapper); // 分页查
userMapper.insert(user); // 插入
userMapper.updateById(user); // 按 ID 更新
userMapper.deleteById(1L); // 按 ID 删除
userMapper.selectOne(wrapper); // 查单条
userMapper.selectCount(wrapper); // 计数
Wrapper 条件构造器
这是 MyBatis-Plus 最强的功能——用 Java 链式调用替代 XML 中复杂的 <if> 标签:
<!-- 传统 MyBatis XML:if 标签地狱 -->
<select id="findUsers">
SELECT * FROM user WHERE 1=1
<if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if>
<if test="age != null">AND age > #{age}</if>
<if test="email != null">AND email = #{email}</if>
</select>
// MyBatis-Plus LambdaQueryWrapper:链式调用,类型安全
LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
.like(StringUtils.isNotBlank(name), User::getName, name)
.gt(age != null, User::getAge, age)
.eq(StringUtils.isNotBlank(email), User::getEmail, email)
.orderByDesc(User::getCreateTime);
List<User> users = userMapper.selectList(wrapper);
优势:
- 类型安全:
User::getName是方法引用,编译时就能检查字段是否存在 - 条件控制:第一个 boolean 参数控制是否拼接该条件
- IDE 补全:字段名、方法名都有自动补全,不用查表结构
- 无 XML:减少文件切换
常用 Wrapper 操作
// 范围查询
wrapper.between(User::getAge, 18, 60);
wrapper.in(User::getStatus, 1, 2, 3);
// 子查询
wrapper.inSql(User::getId, "SELECT user_id FROM order WHERE amount > 1000");
// 嵌套条件
wrapper.and(w -> w.lt(User::getAge, 30).or().gt(User::getAge, 50));
// 排序
wrapper.orderByAsc(User::getSortOrder);
// 指定查询字段(避免 SELECT *)
wrapper.select(User::getId, User::getName);
分页插件
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
// 使用
Page<User> page = userMapper.selectPage(
new Page<>(1, 20), // 第1页,每页20条
wrapper
);
page.getRecords(); // 当前页数据
page.getTotal(); // 总记录数
page.getPages(); // 总页数
物理分页:插件在底层自动生成带 LIMIT 的 SQL,不是一次性查出所有数据再内存分页。性能上没有区别。
陷阱和建议
-
大批量插入不要用 BaseMapper:
saveBatch是逐条 insert,几万条数据性能很差。大批量插入建议手写 MyBatis 的 foreach insert 或使用 JDBC batch。 -
Wrapper 写复杂查询:当查询逻辑太复杂(多表 JOIN、group by、having)时,还是回到 MyBatis XML 写 SQL。Warpper 适合单表简单查询。
-
自动填充:MyBatis-Plus 支持
@TableField(fill = FieldFill.INSERT),可以自动填充 createTime/updateTime 字段。但要注意 UPDATE 时 updateTime 的自动填充。 -
逻辑删除:
@TableLogic注解实现逻辑删除,查询时自动拼接deleted=0条件。适合需要保留删除记录的场景。