在后端开发中,数据库操作是核心环节,传统 MyBatis 需手动编写 XML 映射文件与 SQL,开发效率低、代码冗余。MyBatis-Plus(简称 MP)作为 MyBatis 的增强工具,在保留 MyBatis 特性的基础上,提供自动生成 CRUD 接口、条件构造器、分页插件、逻辑删除等功能,可大幅简化数据库操作代码,提升开发效率,是企业级开发的首选数据访问框架。
本文聚焦 SpringBoot 集成 MyBatis-Plus 的实战落地,从环境搭建、基础 CRUD、条件构造器、分页插件、代码生成器,到复杂查询与性能优化,全程嵌入代码教学,帮你快速掌握 MyBatis-Plus 核心技能,实现高效数据库操作。
一、核心认知:MyBatis-Plus 核心价值与优势
1. 核心优势
- 高效开发:自动生成 CRUD 接口与 SQL,无需手动编写 XML 与基础 SQL;
- 功能强大:提供条件构造器、分页插件、逻辑删除、乐观锁等实用功能;
- 低侵入性:完全兼容 MyBatis,原有 MyBatis 项目可无缝迁移;
- 易于扩展:支持自定义 SQL、XML 映射文件,适配复杂业务场景;
- 性能优异:底层优化 SQL 生成逻辑,避免冗余查询,性能与 MyBatis 一致。
2. 核心适用场景
- 常规 CRUD 场景:单表增删改查,无需编写 SQL;
- 复杂条件查询:多条件过滤、排序、模糊查询,通过条件构造器简化;
- 分页查询:自动分页,无需手动编写分页 SQL;
- 批量操作:批量新增、更新、删除,提升批量处理效率;
- 数据安全:逻辑删除替代物理删除,保留数据痕迹,便于恢复。
3. MyBatis-Plus 核心组件
- BaseMapper:封装单表 CRUD 方法,Mapper 接口继承后直接使用;
- IService:封装 Service 层常用方法(含批量操作),Service 接口继承后可快速开发;
- 条件构造器(QueryWrapper/LambdaQueryWrapper):构建复杂查询条件,替代手动编写 WHERE 子句;
- 代码生成器:自动生成 Entity、Mapper、Service、Controller 层代码,减少重复工作。
二、核心实战一:环境搭建与基础配置
1. 引入依赖(Maven)
xml
<!-- MyBatis-Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok(简化实体类编写) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 代码生成器依赖(可选) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 代码生成器模板依赖(Velocity) -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
2. 配置文件(application.yml)
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mp_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Plus 配置
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml # Mapper XML 文件路径
type-aliases-package: com.example.mp.entity # 实体类别名包路径
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰命名(如 user_name → userName)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志(开发环境开启,生产环境关闭)
global-config:
db-config:
id-type: auto # 主键生成策略(auto:自增,none:无策略,input:手动输入)
logic-delete-field: isDeleted # 逻辑删除字段名
logic-delete-value: 1 # 逻辑删除值(1 表示已删除)
logic-not-delete-value: 0 # 未删除值(0 表示未删除)
3. 启动类配置(扫描 Mapper 接口)
java
运行
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mp.mapper") // 扫描 Mapper 接口所在包
public class MyBatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatisPlusApplication.class, args);
}
}
三、核心实战二:基础 CRUD 操作(BaseMapper + IService)
以用户表(t_user)为例,实现单表增删改查,无需编写 SQL。
1. 实体类(Entity)
java
运行
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_user") // 对应数据库表名
public class User {
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
@TableField("user_name") // 对应数据库字段名(下划线转驼峰可省略,不一致时需指定)
private String userName;
private String password;
private Integer age;
private String email;
@TableLogic // 逻辑删除字段(自动处理删除逻辑)
private Integer isDeleted;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时自动填充
private LocalDateTime updateTime;
}
2. 自动填充配置(处理创建时间、更新时间)
java
运行
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时自动填充
@Override
public void insertFill(MetaObject metaObject) {
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
// 更新时自动填充
@Override
public void updateFill(MetaObject metaObject) {
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
3. Mapper 接口(继承 BaseMapper)
java
运行
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mp.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 无需编写方法,BaseMapper 已封装 CRUD 接口
}
4. Service 层(继承 IService,支持批量操作)
(1)Service 接口
java
运行
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mp.entity.User;
public interface UserService extends IService<User> {
// 可自定义业务方法,基础 CRUD 由 IService 提供
}
(2)Service 实现类
java
运行
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mp.entity.User;
import com.example.mp.mapper.UserMapper;
import com.example.mp.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 无需实现基础方法,ServiceImpl 已封装
}
5. 基础 CRUD 实战代码
java
运行
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mp.entity.User;
import com.example.mp.service.UserService;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// ✅ 新增用户
@PostMapping
public boolean addUser(@RequestBody User user) {
return userService.save(user);
}
// ✅ 批量新增用户
@PostMapping("/batch")
public boolean batchAddUser(@RequestBody List<User> userList) {
return userService.saveBatch(userList);
}
// ✅ 根据ID更新用户
@PutMapping
public boolean updateUser(@RequestBody User user) {
return userService.updateById(user);
}
// ✅ 根据ID删除用户(逻辑删除)
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.removeById(id);
}
// ✅ 根据ID查询用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
// ✅ 查询所有用户(排除已逻辑删除的)
@GetMapping("/list")
public List<User> getUserList() {
return userService.list();
}
// ✅ 条件查询(查询年龄大于20的用户)
@GetMapping("/list/age")
public List<User> getUserListByAge() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20); // gt:大于(greater than)
return userService.list(queryWrapper);
}
}
四、核心实战三:条件构造器与复杂查询
MyBatis-Plus 提供 QueryWrapper(字符串字段名)和 LambdaQueryWrapper(Lambda 表达式,避免字段名写错)两种条件构造器,适配复杂查询场景。
1. LambdaQueryWrapper 实战(推荐,类型安全)
java
运行
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.mp.entity.User;
import com.example.mp.service.UserService;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user/query")
public class UserQueryController {
@Resource
private UserService userService;
// 多条件查询:年龄在20-30之间,邮箱包含"xxx.com",按年龄降序排序
@GetMapping("/complex")
public List<User> getComplexUserList() {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.between(User::getAge, 20, 30) // 年龄在20-30之间
.like(User::getEmail, "xxx.com") // 邮箱包含"xxx.com"
.orderByDesc(User::getAge); // 按年龄降序
return userService.list(lambdaQueryWrapper);
}
// 模糊查询+非空判断:用户名模糊匹配,年龄不为空
@GetMapping("/like")
public List<User> getUserListByLike(@RequestParam String userName) {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(User::getUserName, userName) // 模糊匹配(%userName%)
.isNotNull(User::getAge); // 年龄不为空
return userService.list(lambdaQueryWrapper);
}
// 多条件或查询:用户名包含"张" 或 年龄大于30
@GetMapping("/or")
public List<User> getUserListByOr() {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(User::getUserName, "张")
.or() // 或条件
.gt(User::getAge, 30);
return userService.list(lambdaQueryWrapper);
}
}
2. 分页查询(配置分页插件)
(1)分页插件配置类
java
运行
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();
// 添加分页插件,指定数据库类型(MySQL)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
(2)分页查询实战
java
运行
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.example.mp.entity.User;
import com.example.mp.service.UserService;
import javax.annotation.Resource;
@RestController
@RequestMapping("/user/page")
public class UserPageController {
@Resource
private UserService userService;
// 分页查询:页码从1开始,每页10条数据
@GetMapping
public IPage<User> getUserPage(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize
) {
Page<User> page = new Page<>(pageNum, pageSize);
// 分页+条件查询(年龄大于20)
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.gt(User::getAge, 20);
return userService.page(page, lambdaQueryWrapper);
}
}
五、核心实战四:代码生成器(自动生成全量代码)
MyBatis-Plus 代码生成器可根据数据库表自动生成 Entity、Mapper、Service、Controller 层代码,大幅减少重复开发工作。
1. 代码生成器实战代码
java
运行
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/mp_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC", "root", "123456")
// 1. 全局配置
.globalConfig(builder -> {
builder.author("developer") // 作者
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 输出目录
.commentDate("yyyy-MM-dd HH:mm:ss") // 注释日期
.disableOpenDir(); // 生成后不打开目录
})
// 2. 包配置
.packageConfig(builder -> {
builder.parent("com.example.mp") // 父包名
.moduleName("generator") // 模块名(可选)
.entity("entity") // 实体类包名
.mapper("mapper") // Mapper 包名
.service("service") // Service 包名
.controller("controller") // Controller 包名
.xml("mapper.xml") // Mapper XML 包名(默认在 resources 下)
.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper"));
})
// 3. 策略配置
.strategyConfig(builder -> {
builder.addInclude("t_user", "t_order") // 要生成代码的数据库表名(多个表用逗号分隔)
.addTablePrefix("t_") // 表前缀(生成实体类时去掉前缀,如 t_user → User)
.entityBuilder()
.enableLombok() // 开启 Lombok
.enableTableFieldAnnotation() // 开启字段注解
.logicDeleteColumnName("is_deleted") // 逻辑删除字段名
.controllerBuilder()
.enableRestStyle() // 开启 RestController 风格
.enableHyphenStyle(); // 开启 URL 下划线转驼峰(如 /user-list)
})
// 4. 模板引擎配置(Velocity)
.templateEngine(new VelocityTemplateEngine())
// 5. 执行生成
.execute();
}
}
六、避坑指南
坑点 1:下划线转驼峰失效,字段映射错误
表现:数据库字段 user_name 无法映射到实体类 userName,查询结果为 null;✅ 解决方案:确保配置文件中开启 map-underscore-to-camel-case: true,实体类字段名与数据库字段名符合驼峰规则,不一致时通过 @TableField 指定字段名。
坑点 2:逻辑删除失效,数据被物理删除
表现:调用 removeById 方法后,数据从数据库中直接删除,而非更新逻辑删除字段;✅ 解决方案:确保实体类对应字段添加 @TableLogic 注解,配置文件中指定逻辑删除字段名与值,且删除方法调用的是 MyBatis-Plus 封装的 remove 系列方法。
坑点 3:分页查询失效,返回所有数据
表现:分页查询时未分页,返回全量数据;✅ 解决方案:确保已配置分页插件 MybatisPlusInterceptor,且分页查询使用 page 方法,传入 Page 对象。
坑点 4:条件构造器字段名写错,查询无结果
表现:使用 QueryWrapper 时,字段名拼写错误,导致查询无数据;✅ 解决方案:优先使用 LambdaQueryWrapper(通过 Lambda 表达式获取字段名,编译期校验),避免手动编写字符串字段名。
七、终极总结:MyBatis-Plus 实战的核心是「简化开发 + 规范操作」
MyBatis-Plus 实战的核心价值是通过自动化工具与封装方法,简化数据库操作代码,减少重复开发工作,同时通过规范的配置与 API 设计,提升代码可读性与可维护性。企业级开发中,需结合业务场景合理使用其功能,平衡「开发效率」与「代码灵活性」。
核心原则总结:
- 优先使用封装方法:常规 CRUD、分页、批量操作优先使用 MyBatis-Plus 封装方法,避免重复编写 SQL;
- 条件查询选对构造器:简单查询用
QueryWrapper,复杂查询用LambdaQueryWrapper,确保类型安全; - 规范表设计:统一表前缀、逻辑删除字段、时间字段,便于代码生成器自动生成规范代码;
- 性能优化适配:批量操作避免一次性处理过多数据,分页查询合理设置每页条数,复杂查询可自定义 SQL 优化性能。
记住:MyBatis-Plus 是 MyBatis 的增强而非替代,复杂业务场景(如多表联查、复杂存储过程)仍可结合自定义 XML 与 SQL 实现,充分发挥其灵活性。