MyBatis-Plus全指南(2026最新版)
作者:技术笔记 | 日期:2026-01-25 | 分类:ORM框架、Java开发、数据库操作
本文专为Java后端开发者打造,聚焦MyBatis-Plus(简称MP)的核心用法与企业级实践,从基础集成到高级特性全覆盖。全文包含20+核心API、10大实操场景、30+代码片段,适配Spring Boot 3.x环境,既适合新手快速入门,也可作为资深开发者的进阶参考手册,建议收藏备用。
一、MyBatis-Plus核心认知
1.1 什么是MyBatis-Plus
MyBatis-Plus是基于MyBatis的增强工具,核心定位是“简化MyBatis开发”,在保留MyBatis原生功能的基础上,提供了CRUD接口自动生成、条件构造器、分页插件、逻辑删除等一系列实用特性,无需编写大量XML映射文件和重复SQL,大幅提升数据库操作效率。
MyBatis-Plus由国内团队苞米豆(baomidou)开发维护,完全兼容MyBatis生态,支持所有MyBatis原生用法,同时提供了更简洁的API和更丰富的功能扩展,已成为国内Java项目中ORM框架的首选方案之一。
1.2 核心优势
-
零侵入增强:不改变MyBatis原有架构,无需修改现有代码即可集成,平滑过渡;
-
CRUD自动生成:内置BaseMapper接口,提供全套CRUD方法,无需编写XML和SQL;
-
强大条件构造器:通过Lambda表达式或API构建复杂查询条件,替代繁琐的XML条件拼接;
-
丰富插件支持:内置分页、逻辑删除、乐观锁、性能分析等插件,开箱即用;
-
多数据库适配:支持MySQL、Oracle、SQL Server、PostgreSQL等主流数据库,适配灵活;
-
代码生成器:可自动生成Entity、Mapper、Service、Controller层代码,减少重复编码。
1.3 适用场景
MyBatis-Plus适用于所有使用MyBatis的Java项目,尤其适合以下场景:
-
快速开发项目:需减少重复SQL编写,提升开发效率;
-
复杂查询场景:需动态构建查询条件,避免XML中繁琐的条件判断;
-
微服务项目:轻量化ORM工具,适配微服务架构的简洁性需求;
-
团队协作项目:统一数据库操作规范,降低代码维护成本;
-
多数据库适配项目:无需手动修改SQL即可适配不同数据库。
1.4 技术选型对比
|
对比维度 |
MyBatis(原生) |
MyBatis-Plus |
Hibernate |
|---|---|---|---|
|
核心定位 |
轻量级ORM,手动编写SQL |
MyBatis增强,自动生成SQL |
全自动化ORM,无需编写SQL |
|
SQL控制度 |
高,完全手动控制 |
中高,自动生成+手动扩展 |
低,自动生成,难优化 |
|
开发效率 |
低,需编写大量XML/SQL |
高,CRUD自动生成 |
高,全自动化映射 |
|
灵活性 |
高,适配复杂业务场景 |
高,兼容MyBatis原生扩展 |
低,复杂场景适配困难 |
|
学习成本 |
中,需掌握SQL和XML |
中低,基于MyBatis,易于上手 |
高,需掌握HQL和复杂配置 |
二、MyBatis-Plus集成步骤(核心)
本节以“Spring Boot 3.x + Maven + MySQL 8.x”环境为例,讲解MyBatis-Plus的完整集成流程,其他环境(如Gradle、Oracle)仅需微调依赖和配置。
2.1 环境准备
-
JDK:17+(Spring Boot 3.x强制要求);
-
Spring Boot:3.0.x及以上(本文使用3.3.2稳定版);
-
数据库:MySQL 8.0+(或其他主流数据库);
-
构建工具:Maven 3.6+;
-
IDE:IntelliJ IDEA(推荐)。
2.2 引入依赖
在pom.xml中添加MyBatis-Plus核心依赖和数据库驱动依赖,无需额外引入MyBatis依赖(MP已内置):
《!-- MyBatis-Plus核心依赖 --》
《dependency》
《groupId》com.baomidou《/groupId》
《artifactId》mybatis-plus-boot-starter《/artifactId》
《version》3.5.5《/version》 <!-- 稳定版,适配Spring Boot 3.x -->
《/dependency》
《!-- MySQL驱动依赖 --》
《dependency》
《groupId》com.mysql《/groupId》
《artifactId》mysql-connector-j《/artifactId》
《scope》runtime《/scope》
《/dependency》
《!-- 可选: lombok,简化实体类编写 --》
《dependency》
《groupId》org.projectlombok《/groupId》
《artifactId》lombok《/artifactId》
《optional》true《/optional》
《/dependency》
说明:MyBatis-Plus版本需与Spring Boot版本适配,Spring Boot 3.x对应MP 3.5.3+版本,避免版本冲突。
2.3 基础配置
MyBatis-Plus的配置主要分为数据库连接配置和MP专属配置,通过application.yml文件配置,简洁高效。
2.3.1 数据库连接配置
配置MySQL数据库连接信息,适配MySQL 8.x驱动:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8.x驱动类
url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: root # 数据库用户名
password: 123456 # 数据库密码
2.3.2 MyBatis-Plus专属配置
添加MP核心配置,包括Mapper扫描路径、日志打印、主键策略等:
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml # Mapper XML文件扫描路径(可选)
type-aliases-package: com.example.mpdemo.entity # 实体类别名包路径,简化XML中的类引用
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰命名映射(默认开启)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志打印方式,控制台输出SQL
global-config:
db-config:
id-type: auto # 主键生成策略:auto为数据库自增,可选ASSIGN_ID(雪花算法)等
table-prefix: mp_ # 数据库表名前缀,实体类无前缀时自动拼接(可选)
2.4 核心目录结构
集成完成后,项目核心目录结构如下,遵循分层开发规范:
com.example.mpdemo
├── entity # 实体类(对应数据库表)
│ └── User.java
├── mapper # Mapper接口(继承BaseMapper)
│ └── UserMapper.java
├── service # 业务层
│ ├── UserService.java # 接口
│ └── impl # 实现类
│ └── UserServiceImpl.java
├── controller # 控制层
│ └── UserController.java
└── MpDemoApplication.java # 启动类
2.5 启动类配置
在Spring Boot启动类上添加@MapperScan注解,指定Mapper接口扫描路径,无需在每个Mapper接口上添加@Mapper注解:
package com.example.mpdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mpdemo.mapper") // 扫描Mapper接口包路径
public class MpDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MpDemoApplication.class, args);
}
}
三、核心功能使用(重点)
本节讲解MyBatis-Plus的核心功能,包括实体类映射、BaseMapper CRUD、条件构造器、分页插件等,配套完整代码示例,可直接复制落地。
3.1 实体类映射
实体类是数据库表的映射,通过MP注解指定表名、字段名、主键策略等,结合Lombok可大幅简化代码。
3.1.1 常用注解
-
@TableName:指定数据库表名(实体类名与表名不一致时使用);
-
@TableId:指定主键字段,配置主键生成策略;
-
@TableField:指定普通字段,处理字段名不一致、忽略字段等场景;
-
@TableLogic:指定逻辑删除字段。
3.1.2 实体类示例
假设数据库存在表mp_user(对应实体类User),表结构如下:
CREATE TABLE mp_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT, # 主键自增
user_name VARCHAR(20) NOT NULL, # 用户名(下划线命名)
age INT, # 年龄
email VARCHAR(50), # 邮箱
create_time DATETIME DEFAULT NOW(), # 创建时间
is_deleted TINYINT DEFAULT 0 # 逻辑删除字段(0未删,1已删)
);
对应的实体类编写:
package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data // Lombok注解,自动生成getter、setter、toString等方法
// @TableName("mp_user") // 若实体类名与表名一致(忽略前缀)可省略,此处mp_为全局前缀
public class User {
@TableId(type = IdType.AUTO) // 主键自增策略,与全局配置一致可省略
private Long id;
// 字段名不一致(实体类驼峰,数据库下划线),开启全局下划线转驼峰可省略
private String userName;
private Integer age;
private String email;
// 自动填充创建时间,需配合自动填充插件使用
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
// 逻辑删除字段,0未删,1已删
@TableLogic
private Integer isDeleted;
}
3.2 BaseMapper CRUD操作
MyBatis-Plus提供BaseMapper接口,包含全套CRUD方法,Mapper接口只需继承BaseMapper,无需编写任何方法和XML,即可实现数据库操作。
3.2.1 Mapper接口定义
package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
// 继承BaseMapper,指定实体类泛型
public interface UserMapper extends BaseMapper<User> {
// 无需编写方法,BaseMapper已提供全套CRUD
}
3.2.2 核心CRUD方法示例
在Service或Controller中注入UserMapper,直接调用方法即可,以下为常用方法示例:
package com.example.mpdemo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
// 1. 新增用户
@GetMapping("/user/add")
public String addUser() {
User user = new User();
user.setUserName("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
// insert方法返回受影响行数
int rows = userMapper.insert(user);
return rows > 0 ? "新增成功" : "新增失败";
}
// 2. 根据ID查询用户
@GetMapping("/user/{id}")
public User getUserById(@PathVariable Long id) {
// selectById根据主键查询
return userMapper.selectById(id);
}
// 3. 查询所有用户
@GetMapping("/user/list")
public List<User> getUserList() {
// selectList传入null表示无查询条件,查询所有
return userMapper.selectList(null);
}
// 4. 根据ID修改用户
@GetMapping("/user/update/{id}")
public String updateUser(@PathVariable Long id) {
User user = new User();
user.setId(id);
user.setAge(26); // 仅修改年龄字段
int rows = userMapper.updateById(user);
return rows > 0 ? "修改成功" : "修改失败";
}
// 5. 根据ID删除用户(逻辑删除)
@GetMapping("/user/delete/{id}")
public String deleteUser(@PathVariable Long id) {
int rows = userMapper.deleteById(id);
return rows > 0 ? "删除成功" : "删除失败";
}
}
3.3 条件构造器(QueryWrapper/LambdaQueryWrapper)
当需要复杂查询条件(如多条件筛选、排序、模糊查询)时,可使用MP提供的条件构造器,替代XML中的SQL条件拼接,支持Lambda表达式,避免字段名硬编码。
3.3.1 QueryWrapper(普通方式)
通过字段名字符串构建条件,适用于简单场景:
// 多条件查询:年龄大于20且邮箱不为空,按年龄降序排序
@GetMapping("/user/list/condition")
public List<User> getUserByCondition() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 年龄 > 20
queryWrapper.gt("age", 20);
// 邮箱不为空
queryWrapper.isNotNull("email");
// 按年龄降序排序
queryWrapper.orderByDesc("age");
return userMapper.selectList(queryWrapper);
}
3.3.2 LambdaQueryWrapper(推荐方式)
通过Lambda表达式构建条件,避免字段名硬编码,支持编译期校验:
// 模糊查询:用户名包含"张",年龄在18-30之间,按创建时间升序排序
@GetMapping("/user/list/lambda")
public List<User> getUserByLambda() {
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
// 用户名模糊查询(包含"张")
lambdaWrapper.like(User::getUserName, "张");
// 年龄在18-30之间(闭区间)
lambdaWrapper.between(User::getAge, 18, 30);
// 按创建时间升序排序
lambdaWrapper.orderByAsc(User::getCreateTime);
return userMapper.selectList(lambdaWrapper);
}
3.3.3 常用条件方法
|
方法名 |
说明 |
示例 |
|---|---|---|
|
eq |
等于(=) |
eq("age", 25) → age = 25 |
|
ne |
不等于(≠) |
ne("age", 25) → age ≠ 25 |
|
gt |
大于(>) |
gt("age", 20) → age > 20 |
|
ge |
大于等于(≥) |
ge("age", 20) → age ≥ 20 |
|
lt |
小于(<) |
lt("age", 30) → age < 30 |
|
le |
小于等于(≤) |
le("age", 30) → age ≤ 30 |
|
like |
模糊查询(%值%) |
like("userName", "张") → user_name like '%张%' |
|
between |
区间查询(值1到值2) |
between("age", 18, 30) → age between 18 and 30 |
|
orderByAsc |
升序排序 |
orderByAsc("age") → order by age asc |
|
orderByDesc |
降序排序 |
orderByDesc("age") → order by age desc |
3.4 分页插件
MyBatis-Plus内置分页插件,无需编写分页SQL,只需配置插件并使用Page对象即可实现分页查询,支持物理分页(而非内存分页),性能更优。
3.4.1 配置分页插件
创建MyBatis-Plus配置类,注册分页插件:
package com.example.mpdemo.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();
// 添加分页插件,指定数据库类型(MySQL)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
3.4.2 分页查询示例
使用Page对象指定页码和每页条数,结合条件构造器实现分页:
// 分页查询:第1页,每页10条,条件为年龄大于20
@GetMapping("/user/page")
public Page<User> getUserPage() {
// Page<T>(当前页码, 每页条数),页码从1开始
Page<User> page = new Page<>(1, 10);
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.gt(User::getAge, 20);
// selectPage返回Page对象,包含分页信息和数据列表
Page<User> userPage = userMapper.selectPage(page, lambdaWrapper);
// 分页信息:总条数、总页数、当前页码、每页条数
System.out.println("总条数:" + userPage.getTotal());
System.out.println("总页数:" + userPage.getPages());
return userPage;
}
四、高级特性
本节讲解MyBatis-Plus的高级特性,包括Service层封装、逻辑删除、自动填充、乐观锁等,满足企业级开发的复杂需求。
4.1 Service层封装
MyBatis-Plus提供IService和ServiceImpl接口/类,封装了更丰富的业务层方法(如批量操作、条件查询),比BaseMapper更适合业务层使用,遵循“Service+Mapper”分层规范。
4.1.1 Service接口与实现类
// Service接口,继承IService
package com.example.mpdemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mpdemo.entity.User;
public interface UserService extends IService<User> {
// 可添加自定义业务方法
List<User> getUserByAgeRange(Integer minAge, Integer maxAge);
}
// Service实现类,继承ServiceImpl,注入Mapper
package com.example.mpdemo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import com.example.mpdemo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 实现自定义方法
@Override
public List<User> getUserByAgeRange(Integer minAge, Integer maxAge) {
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.between(User::getAge, minAge, maxAge);
return list(lambdaWrapper); // list方法来自IService
}
}
4.1.2 Service层常用方法
-
saveBatch:批量新增;
-
updateBatchById:批量修改(根据ID);
-
removeByIds:批量删除(根据ID集合);
-
list:查询所有(可结合条件构造器);
-
page:分页查询;
-
count:统计数量(可结合条件构造器)。
4.2 逻辑删除
逻辑删除是指不物理删除数据库记录,而是通过修改标记字段(如is_deleted)表示删除状态,便于数据恢复和历史查询。MyBatis-Plus可自动拦截删除和查询操作,无需手动处理标记字段。
4.2.1 配置逻辑删除
方式1:application.yml全局配置(推荐):
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDeleted # 逻辑删除字段名(实体类字段名)
logic-delete-value: 1 # 删除状态值
logic-not-delete-value: 0 # 未删除状态值
方式2:实体类字段添加@TableLogic注解(优先级高于全局配置):
@TableLogic(value = "0", delval = "1") // value未删值,delval已删值
private Integer isDeleted;
4.2.2 逻辑删除效果
配置完成后,调用deleteById方法时,MP会自动将SQL改为更新操作:
// 原SQL(物理删除):DELETE FROM mp_user WHERE id = ?
// 实际执行SQL(逻辑删除):UPDATE mp_user SET is_deleted = 1 WHERE id = ?
同时,查询操作会自动添加条件is_deleted = 0,过滤已删除数据:
// 原SQL:SELECT * FROM mp_user
// 实际执行SQL:SELECT * FROM mp_user WHERE is_deleted = 0
4.3 自动填充
对于创建时间、修改时间等公共字段,可通过MyBatis-Plus的自动填充功能,在新增/修改时自动赋值,无需手动设置。
4.3.1 配置自动填充处理器
创建自动填充处理器,实现MetaObjectHandler接口:
package com.example.mpdemo.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component // 交给Spring管理
public class MyMetaObjectHandler implements MetaObjectHandler {
// 新增时自动填充
@Override
public void insertFill(MetaObject metaObject) {
// 填充创建时间字段(实体类字段名:createTime)
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
// 修改时自动填充(可选)
@Override
public void updateFill(MetaObject metaObject) {
// 填充修改时间字段(实体类字段名:updateTime)
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
4.3.2 实体类配置填充字段
在实体类字段上添加@TableField(fill = ...)注解,指定填充时机:
@TableField(fill = FieldFill.INSERT) // 仅新增时填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.UPDATE) // 仅修改时填充
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 新增和修改时都填充
private LocalDateTime operateTime;
4.4 乐观锁
乐观锁用于解决并发更新冲突问题,通过版本号字段控制,当更新时检查版本号是否一致,一致则更新并递增版本号,不一致则更新失败。MyBatis-Plus内置乐观锁插件,开箱即用。
4.4.1 配置乐观锁插件
在MyBatis-Plus配置类中添加乐观锁插件:
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
4.4.2 实体类配置版本字段
在实体类中添加版本字段,并添加@Version注解:
@Version // 乐观锁版本号字段
private Integer version; // 版本号,初始值为1
4.4.3 乐观锁使用示例
// 并发更新场景:查询用户后修改年龄,版本号一致则更新成功
@GetMapping("/user/update/optimistic")
public String updateWithOptimisticLock(Long id) {
// 1. 查询用户,获取当前版本号
User user = userService.getById(id);
// 2. 修改字段
user.setAge(user.getAge() + 1);
// 3. 更新操作,MP自动检查版本号
boolean success = userService.updateById(user);
return success ? "更新成功" : "更新失败(并发冲突)";
}
// 实际执行SQL:UPDATE mp_user SET age=?, version=version+1 WHERE id=? AND version=?
五、常见问题与解决方案
5.1 Mapper接口注入失败
-
原因1:未在启动类添加@MapperScan注解,或扫描路径错误;
-
原因2:Mapper接口未继承BaseMapper,或泛型指定错误;
-
解决方案:检查@MapperScan路径,确保Mapper接口继承BaseMapper并指定正确实体类泛型。
5.2 分页插件不生效
-
原因1:未注册分页插件,或插件配置错误;
-
原因2:使用selectList而非selectPage方法,未传入Page对象;
-
解决方案:注册分页插件并指定数据库类型,使用selectPage方法并传入Page对象。
5.3 逻辑删除后仍查询到已删除数据
-
原因1:未配置逻辑删除字段或状态值;
-
原因2:实体类字段未添加@TableLogic注解,且无全局配置;
-
解决方案:配置全局逻辑删除参数,或在实体类字段添加@TableLogic注解。
5.4 自动填充字段未赋值
-
原因1:未创建自动填充处理器,或处理器未交给Spring管理(缺少@Component);
-
原因2:实体类字段未添加@TableField(fill = ...)注解,或填充时机指定错误;
-
解决方案:创建并注册自动填充处理器,为实体类字段配置正确的填充注解。
5.5 乐观锁更新失败
更多推荐



所有评论(0)