MyBatis-Plus 高效开发指南(含代码教学):简化 CRUD,提升数据访问层效率
MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做改变,核心价值是「简化 CRUD 操作、减少重复代码、提升开发效率」—— 通过内置通用 Mapper、条件构造器、分页插件等功能,无需编写 XML 映射文件,即可快速实现数据访问层开发,适配 MySQL、Oracle、PostgreSQL 等多种数据库。
本文聚焦 MyBatis-Plus 实战落地,从环境搭建、基础 CRUD、条件构造器、分页插件,到逻辑删除、批量操作等高频功能,全程嵌入完整代码教学,帮你彻底告别冗余的 XML 配置与 SQL 语句,高效开发数据访问层。
一、核心认知:MyBatis-Plus 核心优势
1. 对比 MyBatis 的核心改进
- 无需编写 XML 映射文件,通用 Mapper 覆盖 80%+ CRUD 场景;
- 内置条件构造器,支持动态 SQL 拼接,无需手动编写 WHERE 语句;
- 自带分页插件、逻辑删除、批量操作等功能,开箱即用;
- 支持主键自动生成、字段填充、乐观锁等高频需求,简化开发;
- 完全兼容 MyBatis 语法,现有 MyBatis 项目可无缝迁移。
2. 适用场景
所有使用 MyBatis 的项目,尤其适合 CRUD 操作频繁、动态 SQL 场景多的业务(如管理系统、电商后台),能大幅减少数据访问层代码量,提升开发效率与代码可维护性。
二、核心实战一:环境搭建(SpringBoot + MyBatis-Plus)
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>
<!-- Lombok(简化实体类) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 配置文件(application.yml)
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Plus 配置
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml # 自定义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:手动输入,ASSIGN_ID:雪花算法)
logic-delete-field: deleted # 逻辑删除字段名
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 操作(无需编写 SQL)
1. 实体类定义(与数据库表对应)
java
运行
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_user") // 对应数据库表名(表名与类名一致可省略)
public class User {
@TableId(type = IdType.AUTO) // 主键,自增策略
private Long id;
private String username; // 用户名(对应表中user_name字段,下划线转驼峰)
private String password; // 密码
private Integer age; // 年龄
private String email; // 邮箱
@TableLogic // 逻辑删除字段(自动触发逻辑删除,而非物理删除)
private Integer deleted;
// 自动填充字段(创建时间、更新时间)
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
2. 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方法
}
3. Service 层封装(可选,推荐使用 IService)
MyBatis-Plus 提供 IService 接口与 ServiceImpl 实现类,封装了更丰富的 CRUD 方法(如批量操作、条件查询),比直接使用 Mapper 更高效。
java
运行
// Service 接口
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mp.entity.User;
public interface UserService extends IService<User> {
// 自定义业务方法(通用方法已在IService中定义)
}
// Service 实现类
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已实现
}
4. 基础 CRUD 实战代码(Controller 层)
java
运行
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mp.entity.User;
import com.example.mp.service.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// ✅ 新增用户(INSERT)
@PostMapping
public boolean addUser(@RequestBody User user) {
return userService.save(user); // 内置方法,自动插入数据
}
// ✅ 删除用户(逻辑删除,UPDATE而非DELETE)
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.removeById(id); // 自动触发逻辑删除,更新deleted=1
}
// ✅ 更新用户(UPDATE)
@PutMapping
public boolean updateUser(@RequestBody User user) {
return userService.updateById(user); // 根据主键更新
}
// ✅ 查询单个用户(SELECT)
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id); // 根据主键查询,自动过滤已删除数据
}
// ✅ 查询所有用户(SELECT * FROM sys_user WHERE deleted=0)
@GetMapping("/list")
public List<User> getUserList() {
return userService.list(); // 内置方法,查询所有未删除数据
}
}
四、核心实战三:条件构造器(动态 SQL 拼接)
MyBatis-Plus 核心优势之一是 QueryWrapper 条件构造器,支持动态拼接 WHERE 语句,无需编写 XML 与 SQL,适配复杂查询场景。
1. 常见条件查询示例
java
运行
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user/query")
public class UserQueryController {
@Resource
private UserService userService;
// ✅ 条件查询:年龄≥20且邮箱包含@test.com的用户
@GetMapping("/listByCondition")
public List<User> listByCondition() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age", 20) // age >= 20
.like("email", "@test.com") // email LIKE '%@test.com%'
.orderByDesc("create_time"); // 按创建时间降序
return userService.list(wrapper);
}
// ✅ 动态条件:根据传入参数拼接SQL(参数为空则不加入条件)
@GetMapping("/listByDynamicCondition")
public List<User> listByDynamicCondition(String username, Integer age) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 用户名不为空则模糊查询
if (username != null && !username.isEmpty()) {
wrapper.like("username", username);
}
// 年龄不为空则查询≥该年龄的用户
if (age != null) {
wrapper.ge("age", age);
}
return userService.list(wrapper);
}
// ✅ 条件更新:更新用户名为admin的密码为123456
@GetMapping("/updateByCondition")
public boolean updateByCondition() {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("username", "admin") // WHERE username = 'admin'
.set("password", "123456"); // SET password = '123456'
return userService.update(wrapper);
}
// ✅ 分页查询(需配置分页插件,下文讲解)
@GetMapping("/page")
public IPage<User> pageQuery(Integer pageNum, Integer pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age", 18);
return userService.page(page, wrapper); // 分页查询,返回分页结果
}
}
2. 常用条件构造器方法(高频必记)
| 方法名 | 作用 | 示例 |
|---|---|---|
| eq | 等于(=) | eq("username", "admin") |
| ne | 不等于(≠) | ne("age", 20) |
| ge/gt | 大于等于 / 大于(≥/>) | ge("age", 18) |
| le/lt | 小于等于 / 小于(≤/<) | lt("age", 30) |
| like | 模糊查询(LIKE) | like("email", "@test.com") |
| in | 包含(IN) | in("id", 1,2,3) |
| orderByAsc/Desc | 升序 / 降序排序 | orderByDesc("create_time") |
| between | 区间查询(BETWEEN) | between("age", 18, 30) |
五、核心实战四:分页插件与字段自动填充
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.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) {
// 填充createTime和updateTime为当前时间
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
// 更新时自动填充
@Override
public void updateFill(MetaObject metaObject) {
// 填充updateTime为当前时间
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
六、核心实战五:批量操作与自定义 SQL
1. 批量操作(内置方法,高效便捷)
java
运行
// 批量新增
List<User> userList = Arrays.asList(new User("user1", "123"), new User("user2", "456"));
boolean result = userService.saveBatch(userList); // 批量插入
// 批量更新
List<User> updateList = userList.stream().peek(user -> user.setAge(20)).collect(Collectors.toList());
userService.updateBatchById(updateList); // 批量更新
// 批量删除
List<Long> idList = Arrays.asList(1L, 2L, 3L);
userService.removeByIds(idList); // 批量删除
2. 自定义 SQL(适配复杂场景,兼容 MyBatis)
当通用方法无法满足需求时,可编写自定义 SQL,支持 XML 或注解方式。
示例 1:注解方式(简单 SQL)
java
运行
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义查询:根据用户名和年龄查询
@Select("SELECT * FROM sys_user WHERE username = #{username} AND age = #{age} AND deleted = 0")
User selectByUsernameAndAge(@Param("username") String username, @Param("age") Integer age);
}
示例 2:XML 方式(复杂 SQL)
- 在 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.example.mp.mapper.UserMapper">
<!-- 自定义复杂查询 -->
<select id="selectUserWithRole" resultType="com.example.mp.entity.UserVO">
SELECT u.*, r.role_name
FROM sys_user u
LEFT JOIN sys_user_role ur ON u.id = ur.user_id
LEFT JOIN sys_role r ON ur.role_id = r.id
WHERE u.deleted = 0
</select>
</mapper>
- 在 Mapper 接口中定义方法:
java
运行
List<UserVO> selectUserWithRole();
七、避坑指南
坑点 1:下划线转驼峰失效,字段映射错误
表现:数据库字段user_name无法映射到实体类userName;✅ 解决方案:在配置文件中开启map-underscore-to-camel-case: true,确保字段名与实体类属性名遵循下划线转驼峰规则。
坑点 2:逻辑删除失效,数据被物理删除
表现:调用removeById后,数据被直接删除(DELETE),而非更新deleted字段;✅ 解决方案:实体类字段添加@TableLogic注解,同时在配置文件中配置逻辑删除字段与值。
坑点 3:分页查询返回总条数为 0,分页失效
表现:分页查询只返回当前页数据,总条数为 0,无法分页;✅ 解决方案:确保已配置分页插件,且分页插件添加到MybatisPlusInterceptor中,同时数据库类型匹配正确。
八、终极总结:MyBatis-Plus 实战的核心是「高效复用」
MyBatis-Plus 不是替代 MyBatis,而是通过「通用封装 + 功能增强」,让开发者从冗余的 CRUD 代码、XML 配置中解放出来,聚焦核心业务逻辑。其实战的核心原则是「能复用不自定义,能自动不手动」—— 最大化利用内置通用方法、条件构造器、插件等功能,减少重复开发。
核心原则总结:
- 优先复用内置方法:BaseMapper 与 IService 已覆盖大部分 CRUD 场景,无需重复编写 SQL;
- 条件构造器简化动态 SQL:复杂查询优先使用 QueryWrapper,避免手动拼接 SQL 导致的错误;
- 插件按需配置:分页、逻辑删除等功能通过插件实现,开箱即用,无需自定义开发;
- 兼容 MyBatis 兜底:复杂场景可无缝切换到自定义 SQL,兼顾高效与灵活。
记住:MyBatis-Plus 的价值在于「提升效率、简化开发」,合理使用它能让数据访问层代码更简洁、更易维护,成为后端开发的「效率神器」。
更多推荐



所有评论(0)