MybatisPlus 超详细教程:从入门到复杂查询(含示例代码)
MybatisPlus (MP) 作为 MyBatis 的增强工具,在简化开发、提高效率方面表现出色,已成为 Java 开发中数据持久层框架的首选之一。它在 MyBatis 的基础上只做增强不做改变,完美兼容原生 MyBatis 的所有功能,并提供了更多便捷的特性,如通用 CRUD、条件构造器、代码生成器等。

本篇博客将带你深入浅出地学习 MybatisPlus,从环境搭建、基本使用到各种复杂查询的实现,并附上详细的示例代码和官方文档链接,助你轻松掌握这个强大的工具。
官方文档是最好的老师,建议收藏: MybatisPlus 官方文档
一、 快速开始:在 Spring Boot 中集成 MybatisPlus
在 Spring Boot 项目中集成 MybatisPlus 非常简单,只需几步即可完成。
1. 添加 Maven 依赖
首先,在你的 pom.xml 文件中添加 MybatisPlus 的启动器依赖。
XML
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.6</version> </dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 配置 application.yml
接下来,在 application.yml 中配置数据库连接信息。
YAML
spring:
datasource:
url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: your_username
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
# 如果你的 Mapper XML 文件放在 `resources/mapper` 目录下
mapper-locations: classpath*:/mapper/**/*.xml
# 实体类所在的包
type-aliases-package: com.your.project.entity
# 开启驼峰命名转换
configuration:
map-underscore-to-camel-case: true
3. 启动类添加 @MapperScan
在你的 Spring Boot 启动类上添加 @MapperScan 注解,指定 Mapper 接口所在的包路径。
Java
package com.your.project;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.your.project.mapper")
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}
二、 核心功能:通用 CRUD 详解
MybatisPlus 强大的地方在于,你只需要创建一个 Mapper 接口并继承 BaseMapper<T>,就能拥有丰富的内置 CRUD 方法,无需编写任何 SQL。
1. 创建实体类 (Entity)
假设我们有一张 user 表。
SQL
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱'
);
对应的实体类 User.java:
Java
package com.your.project.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user") // 指定表名
public class User {
@TableId(type = IdType.AUTO) // 指定主键且自增
private Long id;
private String name;
private Integer age;
private String email;
}
2. 创建 Mapper 接口
Java
package com.your.project.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.your.project.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}
3. 内置 CRUD 方法示例
现在,你可以直接在 Service 层注入 UserMapper 并调用其方法。
Java
@Autowired
private UserMapper userMapper;
// 插入数据
User user = new User();
user.setName("Gemini");
user.setAge(5);
user.setEmail("gemini@google.com");
userMapper.insert(user); // 返回受影响行数,user对象的id会被自动填充
// 根据 ID 查询
User selectedUser = userMapper.selectById(user.getId());
// 查询所有用户
List<User> userList = userMapper.selectList(null); // 传入 null 查询所有
// 根据 ID 更新
User updateUser = new User();
updateUser.setId(user.getId());
updateUser.setAge(6);
userMapper.updateById(updateUser); // 只更新非空的字段
// 根据 ID 删除
userMapper.deleteById(user.getId());
// 批量删除
userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));
4. Service 层封装 (IService & ServiceImpl)
为了更好地组织业务逻辑和利用 MP 的更多功能(如批量操作),推荐使用 MP 提供的 IService 和 ServiceImpl。
创建 IService 接口:
Java
package com.your.project.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.your.project.entity.User;
public interface IUserService extends IService<User> {
// 可以在这里定义自己的业务方法
}
创建 ServiceImpl 实现类:
Java
package com.your.project.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.your.project.entity.User;
import com.your.project.mapper.UserMapper;
import com.your.project.service.IUserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
// 继承 ServiceImpl 后,同样拥有了丰富的 CRUD 方法
// 如 save(), updateById(), list(), removeById() 等
}
使用 ServiceImpl 可以让你的代码结构更清晰,并且它内置了对批量操作的优化处理。
三、 强大的条件构造器:Wrapper
当简单的 CRUD 无法满足需求时,就需要使用条件构造器 Wrapper。Wrapper 是 MybatisPlus 的精髓所在,它能让你以面向对象的方式构建复杂的 SQL WHERE 子句,同时保证类型安全。
我们强烈推荐使用 LambdaQueryWrapper,因为它可以利用 Lambda 表达式,避免硬编码字段名,提高代码的可读性和健壮性。
1. 基本查询示例
Java
@Autowired
private IUserService userService;
// 查询年龄大于 20 岁且姓名中包含 "a" 的用户
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.gt(User::getAge, 20)
.like(User::getName, "a");
List<User> users = userService.list(queryWrapper);
// 查询年龄在 20 到 30 岁之间,且邮箱不为空的用户,按年龄降序排列
LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>();
queryWrapper2.between(User::getAge, 20, 30)
.isNotNull(User::getEmail)
.orderByDesc(User::getAge);
List<User> users2 = userService.list(queryWrapper2);
2. 链式调用
Wrapper 支持链式调用,使代码更加简洁。
Java
List<User> users = userService.lambdaQuery()
.eq(User::getName, "Sandy")
.or()
.lt(User::getAge, 20)
.list();
// SQL: SELECT * FROM user WHERE (name = 'Sandy' OR age < 20)
3. 动态条件查询
在构建搜索功能时,常常需要根据前端传入的参数动态拼接查询条件。
Java
public List<User> search(String name, Integer startAge, Integer endAge) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// StringUtils.isNotBlank 来自 a`pache commons-lang3`
wrapper.like(StringUtils.isNotBlank(name), User::getName, name)
.ge(startAge != null, User::getAge, startAge)
.le(endAge != null, User::getAge, endAge);
return userService.list(wrapper);
}
wrapper 的 like, ge, le 等方法的第一个参数是 boolean 类型,当其为 true 时,该条件才会拼接到 SQL 中。
4. 高级查询
Wrapper 还支持更复杂的查询,如 IN, NOT IN, NESTED (嵌套查询) 等。
Java
// 查询 ID 在 (1, 2, 5) 列表中的用户
userService.lambdaQuery().in(User::getId, Arrays.asList(1L, 2L, 5L)).list();
// 查询 (age > 25 AND name LIKE 'J%') OR (email IS NOT NULL)
userService.lambdaQuery()
.nested(wq -> wq.gt(User::getAge, 25).likeRight(User::getName, "J"))
.or()
.isNotNull(User::getEmail)
.list();
四、 复杂查询:多表连接与自定义 SQL
虽然 Wrapper 能处理大部分单表查询,但在实际业务中,多表连接查询不可避免。MybatisPlus 推荐通过编写自定义 SQL 的方式来处理复杂的多表查询。
这通常需要结合 MyBatis 原生的 XML 映射文件。
1. 场景设定
假设我们有两张表:user (用户表) 和 orders (订单表),一个用户可以有多个订单。现在需要查询每个用户的基本信息以及他们的订单总数。
2. 创建 DTO (Data Transfer Object)
查询结果包含了多个表的数据,不再适合用单个实体类接收。我们需要创建一个 DTO 来封装查询结果。
Java
package com.your.project.dto;
import lombok.Data;
@Data
public class UserOrderCountDTO {
private Long userId;
private String name;
private String email;
private Integer orderCount;
}
3. 在 Mapper 中定义方法
在 UserMapper 接口中添加自定义的查询方法。
Java
package com.your.project.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.your.project.entity.User;
import com.your.project.dto.UserOrderCountDTO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
/**
* 查询用户及其订单总数(分页)
* @param page 分页参数
* @param name 可选的筛选条件:用户名
* @return 分页结果
*/
IPage<UserOrderCountDTO> selectUserWithOrderCount(Page<?> page, @Param("name") String name);
}
4. 编写 Mapper XML 文件
在 resources/mapper/UserMapper.xml 文件中编写对应的 SQL 语句。
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.your.project.mapper.UserMapper">
<select id="selectUserWithOrderCount" resultType="com.your.project.dto.UserOrderCountDTO">
SELECT
u.id AS userId,
u.name,
u.email,
(SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS orderCount
FROM
user u
<where>
<if test="name != null and name != ''">
u.name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
ORDER BY u.id DESC
</select>
</mapper>
注意:
resultType指向我们创建的 DTO 类。- SQL 中的字段名通过
AS别名与 DTO 中的属性名对应。如果数据库字段是下划线命名法而 DTO 是驼峰命名法(如user_id->userId),MP 的驼峰转换配置会自动处理。 @Param("name")注解将方法参数与 XML 中的#{name}对应起来。- 这里使用了子查询,你也可以使用
LEFT JOIN和GROUP BY实现。
5. 分页查询配置与调用
要使用 MybatisPlus 的物理分页功能,需要添加一个配置 Bean。
Java
package com.your.project.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件,并指定数据库类型
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
在 Service 中调用:
Java
public IPage<UserOrderCountDTO> getUserOrderPage(long current, long size, String name) {
Page<UserOrderCountDTO> page = new Page<>(current, size);
return userMapper.selectUserWithOrderCount(page, name);
}
MybatisPlus 的分页插件会自动拦截你的查询,并将其改写为分页 SQL,无需手动编写 LIMIT 子句。
总结
MybatisPlus 以其强大的功能和极低的上手门槛,极大地提升了我们的开发效率。本文从基础的 CRUD 入手,详细介绍了核心的条件构造器 Wrapper 的使用,并演示了如何通过自定义 XML 的方式解决复杂的多表连接查询问题。
掌握 MybatisPlus 的关键在于:
- 熟练使用
BaseMapper和IService处理常规的单表操作。 - 精通
LambdaQueryWrapper构建灵活、安全的动态查询条件。 - 回归 MyBatis 本质,通过编写 XML SQL 和 DTO 来应对复杂的报表和多表查询需求。
希望这篇详细的教程能帮助你更好地在项目中使用 MybatisPlus,编写出更高效、更优雅的数据访问层代码。