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)
  1. 在 resources/mapper 目录下创建 UserMapper.xml;
  2. 编写 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>
  1. 在 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 配置中解放出来,聚焦核心业务逻辑。其实战的核心原则是「能复用不自定义,能自动不手动」—— 最大化利用内置通用方法、条件构造器、插件等功能,减少重复开发。

核心原则总结:

  1. 优先复用内置方法:BaseMapper 与 IService 已覆盖大部分 CRUD 场景,无需重复编写 SQL;
  2. 条件构造器简化动态 SQL:复杂查询优先使用 QueryWrapper,避免手动拼接 SQL 导致的错误;
  3. 插件按需配置:分页、逻辑删除等功能通过插件实现,开箱即用,无需自定义开发;
  4. 兼容 MyBatis 兜底:复杂场景可无缝切换到自定义 SQL,兼顾高效与灵活。

记住:MyBatis-Plus 的价值在于「提升效率、简化开发」,合理使用它能让数据访问层代码更简洁、更易维护,成为后端开发的「效率神器」。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐