SpringBoot 集成 MyBatis-Plus 实战(高效 CRUD 与复杂查询):简化数据库操作

在后端开发中,数据库操作是核心环节,传统 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 设计,提升代码可读性与可维护性。企业级开发中,需结合业务场景合理使用其功能,平衡「开发效率」与「代码灵活性」。

核心原则总结:

  1. 优先使用封装方法:常规 CRUD、分页、批量操作优先使用 MyBatis-Plus 封装方法,避免重复编写 SQL;
  2. 条件查询选对构造器:简单查询用 QueryWrapper,复杂查询用 LambdaQueryWrapper,确保类型安全;
  3. 规范表设计:统一表前缀、逻辑删除字段、时间字段,便于代码生成器自动生成规范代码;
  4. 性能优化适配:批量操作避免一次性处理过多数据,分页查询合理设置每页条数,复杂查询可自定义 SQL 优化性能。

记住:MyBatis-Plus 是 MyBatis 的增强而非替代,复杂业务场景(如多表联查、复杂存储过程)仍可结合自定义 XML 与 SQL 实现,充分发挥其灵活性。

相关推荐
川西胖墩墩1 小时前
开发者友好型AI调试与可观测性工具
人工智能
小白不会Coding1 小时前
一文详解JVM中类的生命周期
java·jvm·类的生命周期
醇氧1 小时前
java.lang.NumberFormatException: For input string: ““
java·开发语言·spring
学统计的程序员1 小时前
一篇文章简述如何安装claude code并接入国产智谱AI大模型
人工智能·ai编程·claude
2501_941333101 小时前
耳机听筒检测与识别 Ear_Piece和Head_Phone目标检测改进版freeanchor_r101_fpn_1x_coco模型_1
人工智能·目标检测·计算机视觉
人工小情绪2 小时前
Antigravity简介
ide·人工智能
sww_10262 小时前
智能问数系统(一):高质量的Text-to-SQL
java·人工智能·ai编程
win x2 小时前
文件操作与io总结
java
好奇龙猫2 小时前
【人工智能学习-AI入试相关题目练习-第六次】
人工智能·学习