Spring Boot 集成 Mybatis-Plus 全面技术实战指南

Spring Boot 为开发者提供了“约定大于配置”的快速开发能力,而 Mybatis-Plus 则基于 MyBatis 进行了深度增强,使数据库 CRUD 操作高度简化。二者结合后,既保证了 MyBatis 的灵活性,又提升了开发效率,是目前企业 Java 开发中主流组合。

在传统 MyBatis 项目中,我们常常需要:

  • 手写 SQL
  • 手写 XML
  • 手写通用 CRUD
  • 维护复杂的 Mapper 映射
  • 配置繁琐(数据源、SqlSessionFactory 等)

Mybatis-Plus 改进了这些痛点,大幅提升开发体验。为了让小白能快速掌握,本章节先构建整体知识框架:

+-------------------------------+
|        Spring Boot 启动       |
+-------------------------------+
               |
               v
+-------------------------------+
|     Mybatis-Plus 自动装配     |
+-------------------------------+
               |
               v
+-----------------------------------------+
|  BaseMapper<T> 与 Service 层两级封装     |
+-----------------------------------------+
               |
               v
+-------------------------------+
|      CRUD、条件构造器、分页      |
+-------------------------------+
               |
               v
+------------------------------+
|          SQL 执行流程         |
+------------------------------+

二、为什么使用 Mybatis-Plus,而不是原生 MyBatis?

1. MyBatis 的问题(痛点)

  • 大量重复 CRUD:每个表都要写 insert/update/select/delete
  • 需要维护 XML
  • 通用功能需要自己实现(分页、乐观锁)
  • 链式查询需要自己封装

2. Mybatis-Plus 的提升点

  • 单表 CRUD 开箱即用
  • 无需 XML(可选)
  • 内置分页、乐观锁、填充字段、代码生成器
  • Lambda 查询更安全
  • 大量且成熟的企业案例

这正是企业中大规模使用 Mybatis-Plus 的主要原因。


三、项目初始化:完整的 Spring Boot + Mybatis-Plus 示例

1. Maven 依赖(必须可用)

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Mybatis-Plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.5</version>
    </dependency>

    <!-- MySQL 连接驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.3.0</version>
    </dependency>

    <!-- Lombok 简化实体代码 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2. application.yml(完整可运行)

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: auto    # 主键自增
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0

3. 数据库建表 SQL(完整可直接执行)

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    age INT,
    email VARCHAR(100),
    deleted TINYINT DEFAULT 0,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

四、使用 Mybatis-Plus 完成基础 CRUD

1. 实体类

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.util.Date;

@Data
@TableName("user")
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;

    private String username;
    private Integer age;
    private String email;

    @TableLogic
    private Integer deleted;

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

2. Mapper 接口(不写 XML)

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;

public interface UserMapper extends BaseMapper<User> {}

3. Service 层

package com.example.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;

public interface UserService extends IService<User> {}

实现类:

package com.example.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

4. Controller 示例

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/add")
    public User add(@RequestBody User user) {
        userService.save(user);
        return user;
    }

    @GetMapping("/{id}")
    public User get(@PathVariable Long id) {
        return userService.getById(id);
    }
}

以上代码可直接运行,这是你最小可用工程的核心结构。


五、条件查询:QueryWrapper 与 LambdaQueryWrapper

Mybatis-Plus 条件构造器是其最大优势之一。

1. 使用 QueryWrapper

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("age", 18)
       .like("username", "张");

List<User> list = userMapper.selectList(wrapper);

2. LambdaQueryWrapper(推荐)

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAge, 18)
       .like(User::getUsername, "张");

List<User> list = userMapper.selectList(wrapper);

3. 复杂示例:条件动态拼接

Integer age = null;
String name = "李";

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(age != null, User::getAge, age)
       .like(name != null, User::getUsername, name);

六、分页查询:Mybatis-Plus 的分页插件

1. 配置分页插件

@Configuration
@MapperScan("com.example.demo.mapper")
public class MpConfig {

    @Bean
    public MybatisPlusInterceptor interceptor() {
        MybatisPlusInterceptor mp = new MybatisPlusInterceptor();
        mp.addInnerInterceptor(new PaginationInnerInterceptor());
        return mp;
    }
}

2. 分页示例

Page<User> page = new Page<>(1, 10);
Page<User> result = userMapper.selectPage(page, new QueryWrapper<>());

返回结构包含:

  • 总数
  • 总页数
  • 当页记录

七、自动填充字段

1. 注解填充

实体类中已经加入:

@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

2. 实现元数据处理器

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }
}

八、逻辑删除:软删除功能

1. 实体类标记

@TableLogic
private Integer deleted;

2. yml 配置

已在 application.yml 配置:

logic-delete-value: 1
logic-not-delete-value: 0

3. 使用

userService.removeById(1L);

此操作并不会删除数据库记录,而是更新 deleted=1。

4. 查询自动过滤 deleted=1


九、代码生成器:自动生成实体、Mapper、Service

1. 完整可运行示例

public class CodeGenerator {

    public static void main(String[] args) {

        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mp_demo",
                "root", "123456")
                .globalConfig(builder -> {
                    builder.author("牛向前")
                           .outputDir(System.getProperty("user.dir") + "/src/main/java");
                })
                .packageConfig(builder -> {
                    builder.parent("com.example.demo");
                })
                .strategyConfig(builder -> {
                    builder.entityBuilder().enableLombok();
                    builder.mapperBuilder().enableMapperAnnotation();
                    builder.serviceBuilder();
                })
                .execute();
    }
}

可自动生成几十个类,大幅提升效率。


十、进阶专题:自定义 SQL、XML、高级条件查询

1. 自定义 SQL(注解方式)

@Select("select * from user where username=#{name}")
List<User> findByName(String name);

2. XML 映射方式

UserMapper.java:

List<User> search(UserQueryDTO dto);

resources/mapper/UserMapper.xml:

<select id="search" resultType="com.example.demo.entity.User">
    SELECT * FROM user
    <where>
        <if test="dto.username != null">
            AND username LIKE CONCAT('%', #{dto.username}, '%')
        </if>
        <if test="dto.age != null">
            AND age = #{dto.age}
        </if>
    </where>
</select>

Mybatis-Plus 完全兼容 MyBatis XML。


十一、Spring Boot 实战案例:用户管理模块

本节整合 Controller + Service + 分页 + 条件查询。

1. 搜索用户接口

@PostMapping("/search")
public Page<User> search(@RequestBody UserQueryDTO dto) {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.like(dto.getUsername() != null, User::getUsername, dto.getUsername());
    return userService.page(new Page<>(dto.getPage(), dto.getSize()), wrapper);
}

DTO:

@Data
public class UserQueryDTO {
    private String username;
    private Integer page = 1;
    private Integer size = 10;
}

输出结构为:

{
  "records": [...],
  "total": 100,
  "pages": 10,
}

十二、常见错误与 Debug 指南

以下错误在企业项目中非常常见:

1. 找不到 Mapper

原因:没加 @MapperScan 或 @Mapper。

解决:

@MapperScan("com.example.demo.mapper")

2. 分页插件不生效

原因:未注册 PaginationInnerInterceptor。


3. 自动填充不生效

原因:没有实现 MetaObjectHandler。


4. 逻辑删除无效

原因:

  • 未加 @TableLogic
  • yml 缺失配置

5. Lambda 查询报错:字段名不存在

原因:实体字段与数据库字段不一致。

解决:

@TableField("db_column")
private String username;

十三、Mybatis-Plus 最佳实践

1. 能用 Lambda 就不要用字符串字段名

避免列名写错。

2. 不推荐全部表都逻辑删除

部分表(日志表)应该使用物理删除。

3. 分页查询必须指定 order by

否则 MySQL 大表分页性能差。


十四、作者经验总结(非常重要)

作为实际参与多个大型项目(电商、物流、SaaS 平台)后台研发的经验,使用 Mybatis-Plus 的最大价值不只是“方便”。更重要的是结构统一、减少低级 Bug、提升团队协作能力。

经验总结如下:

  • 少写 SQL 就是减少 Bug 的最好方式
  • ServiceImpl 的 CRUD 足够用,不要重复封装
  • 条件查询完全用 LambdaQueryWrapper,避免踩坑
  • 分页插件性能稳定,不需要自己造轮子
  • 逻辑删除只是业务补充,不可滥用
  • 自动填充 + 统一字段名 = 大幅提升可维护性

Mybatis-Plus 已经在企业级项目成为事实标准,合理使用能让 Spring Boot 后端开发效率提升 3~5 倍。


正文到此结束
评论插件初始化中...
Loading...