MyBatis-Plus

1. 是什么?

MyBatis-Plus(简称 MP)是一个 基于 MyBatis 的增强工具,在 MyBatis 的基础上只做增强,不做改变。它的目标是 简化开发、提高效率,让开发者“只写 SQL 的 20%,完成 80% 的 CRUD 工作”。

官方口号:为简化开发而生。

MyBatis-Plus 并不是一个独立框架,而是 MyBatis 的插件式扩展。它保留了 MyBatis 的所有特性(如手写 SQL、动态 SQL、结果映射等),同时提供了:

  • 通用 CRUD 封装(无需写 Mapper XML)
  • 条件构造器(Wrapper,链式编程构建 WHERE 条件)
  • 分页插件
  • 自动填充(如创建时间、更新时间)
  • 乐观锁支持
  • 逻辑删除
  • 代码生成器

本质上,MyBatis-Plus = MyBatis + 自动化 CRUD + 实用工具集。

2. 没有之前?

在 MyBatis-Plus 出现之前(项目始于 2016 年),开发者使用 原生 MyBatis 时仍面临以下重复性工作:

问题说明
大量重复的 CRUD XML即使是简单的增删改查,每个实体都要写 <select>, <insert> 等标签,内容高度相似。
手写条件查询繁琐多条件查询需在 XML 中写大量 <if> 标签,或拼接字符串,易出错。
分页需手动处理不同数据库分页语法不同(MySQL 用 LIMIT,Oracle 用 ROWNUM),需自行适配。
公共字段需手动赋值create_time, update_time, create_by 等字段,每次插入/更新都要显式设置。
逻辑删除需改 SQL软删除(is_deleted = 1)需在每个查询中加 AND is_deleted = 0,容易遗漏。
样板代码多Service 层常写 xxxMapper.selectById(id) 这类重复调用。

原生 MyBatis 的典型痛点示例:

<!-- UserMapper.xml -->
<select id="selectByCondition" resultType="User">
  SELECT * FROM user
  <where>
    <if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if>
    <if test="status != null">AND status = #{status}</if>
    AND is_deleted = 0 <!-- 逻辑删除,每处都要加! -->
  </where>
</select>

每个表都要写类似逻辑,维护成本高。

3. 为什么使用?

MyBatis-Plus 的核心价值是:在保留 MyBatis 灵活性的前提下,消灭 90% 的样板代码。

  • 无侵入:仅依赖 MyBatis,不修改其核心机制。
  • 强大的 CRUD 封装:继承 BaseMapper<T> 即可获得 17+ 个通用方法(如 selectById, updateById, delete 等)。
  • 链式条件构造器(Wrapper):用 Java 代码构建 WHERE 条件,类型安全、可读性强。
  • 自动分页:一行配置支持多数据库分页,无需写 LIMITROWNUM
  • 自动填充:插入/更新时自动填充字段(如时间戳、操作人)。
  • 逻辑删除:全局配置后,所有查询自动过滤已删除数据。
  • 乐观锁插件:通过 @Version 注解实现并发控制。
  • 代码生成器:一键生成 Entity、Mapper、Service、Controller,极大提升开发速度。
  • 与 Spring Boot 无缝集成:自动配置,开箱即用。

适用场景:快速开发后台管理系统、CRUD 密集型应用、需要兼顾效率与灵活性的项目。

4. 核心组件 / 概念

组件/概念说明
BaseMapper通用 Mapper 接口,继承后自动获得 CRUD 方法。
IService / ServiceImpl<M, T>通用 Service 层封装,提供批量操作、分页查询等高级方法。
QueryWrapper / UpdateWrapper条件构造器,用于构建 WHERE、SET 子句,支持链式调用。
LambdaQueryWrapper基于 Lambda 表达式的 Wrapper,避免硬编码字段名(类型安全)。
MyMetaObjectHandler自动填充处理器,用于 insertFill / updateFill
PaginationInterceptor(旧版) / MybatisPlusInterceptor(新版)分页插件,注册后 Page<T> 对象自动分页。
@TableName, @TableId, @TableField实体类注解,用于配置表名、主键策略、字段映射、逻辑删除等。
CodeGenerator代码生成器,根据数据库表自动生成全套 CRUD 代码。

5. 使用步骤

步骤 1:添加依赖(Spring Boot 项目)

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.5</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

步骤 2:配置 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
 
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL
  global-config:
    db-config:
      id-type: auto          # 主键自增
      logic-delete-value: 1  # 逻辑删除值(已删除)
      logic-not-delete-value: 0 # 未删除值

步骤 3:定义实体类(Entity)

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
 
@Data
@TableName("user") // 指定表名
public class User {
    @TableId(type = IdType.AUTO) // 主键自增
    private Long id;
 
    private String name;
    private String email;
 
    @TableField(fill = FieldFill.INSERT) // 插入时自动填充
    private LocalDateTime createTime;
 
    @TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时填充
    private LocalDateTime updateTime;
 
    @TableLogic // 逻辑删除字段
    private Integer deleted; // 0-未删除, 1-已删除
}

步骤 4:定义 Mapper 接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
 
@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 无需写任何方法!已继承 selectById, insert, updateById 等
}

步骤 5:定义 Service(可选但推荐)

import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
 
@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IService<User> {
    // 可扩展自定义方法
}

步骤 6:配置自动填充 & 分页插件(Java Config)

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.time.LocalDateTime;
 
// 自动填充处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
    }
 
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
    }
}
 
// 分页插件(MyBatis-Plus 3.4.0+)
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

6. 示例代码(完整 CRUD + 条件查询)

@RestController
@RequestMapping("/user")
public class UserController {
 
    @Autowired
    private UserService userService;
 
    // 1. 新增
    @PostMapping
    public boolean save(@RequestBody User user) {
        return userService.save(user); // 自动填充 createTime/updateTime
    }
 
    // 2. 删除(逻辑删除)
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Long id) {
        return userService.removeById(id); // 实际执行 UPDATE SET deleted = 1
    }
 
    // 3. 修改
    @PutMapping
    public boolean update(@RequestBody User user) {
        return userService.updateById(user); // 自动填充 updateTime
    }
 
    // 4. 查询 by ID
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id) {
        return userService.getById(id); // 自动忽略 deleted=1 的记录
    }
 
    // 5. 条件查询 + 分页
    @GetMapping("/list")
    public IPage<User> list(
        @RequestParam(required = false) String name,
        @RequestParam(defaultValue = "1") int current,
        @RequestParam(defaultValue = "10") int size) {
 
        // 使用 LambdaQueryWrapper 构建条件(类型安全)
        LambdaQueryWrapper<User> query = Wrappers.<User>lambdaQuery()
            .like(StringUtils.isNotBlank(name), User::getName, name);
 
        Page<User> page = new Page<>(current, size);
        return userService.page(page, query);
    }
}

上述代码 无需任何 XML 文件,所有 CRUD 和条件查询均由 MyBatis-Plus 自动生成 SQL。

7. 局限性

尽管 MyBatis-Plus 极大提升了开发效率,但也存在一些限制:

局限说明
仅适用于单表操作复杂多表 JOIN 仍需手写 SQL(可通过 @Select 注解或 XML 补充)。
学习新 API需掌握 Wrapper、IService 等新概念,对纯 MyBatis 用户有学习成本。
过度封装风险初学者可能不了解底层 SQL,导致性能问题(如未加索引的模糊查询)。
版本兼容性不同版本间 API 可能变化较大(如分页插件从 PaginationInterceptor 改为 MybatisPlusInterceptor)。
不适合超复杂业务若 80% 以上都是定制 SQL,MP 的优势会减弱。
调试需看日志自动生成的 SQL 需开启日志才能查看,不如手写直观。

总结

维度内容
是什么MyBatis 的增强工具,提供通用 CRUD、条件构造器、分页等
没有之前原生 MyBatis 需手写大量重复 XML 和条件判断
为什么用消灭样板代码、提升开发效率、保留 MyBatis 灵活性
核心组件BaseMapper, IService, Wrapper, 自动填充, 逻辑删除, 代码生成器
使用步骤依赖 → 配置 → 实体(注解)→ Mapper(继承 BaseMapper)→ Service → 调用
局限性多表查询支持弱、需学习新 API、复杂场景仍需手写 SQL

推荐使用场景:

  • 后台管理系统(Admin System)
  • 快速原型开发(MVP)
  • 单表 CRUD 为主的业务系统

❌ 慎用场景:

  • 高度复杂的 OLAP 报表系统
  • 多表深度关联、频繁使用存储过程的遗留系统

MyBatis-Plus 是当前国内 Java 开发中最流行的持久层解决方案之一,尤其适合追求 开发效率 + 灵活性 的团队。如果已经熟悉 MyBatis,上手 MP 几乎零成本;如果是新手,MP 也能快速上手写出专业级数据访问层。

关联网络

演化日志

  • v0.1 (2026-02-02):补充关联网络、演化日志、附件参考、待办事项

待办事项

  • OLAP 报表系统
  • 存储过程
  • 代码生成器使用、多数据源配置、与 Spring Security 集成