MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做修改,简化单表操作、提升开发效率,是国内企业级开发主流持久层框架。

一、基础入门(环境搭建 + 核心使用)

1. 核心依赖(Maven)

xml

<!-- SpringBoot 整合 MyBatis-Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>
<!-- 数据库驱动(以 MySQL 为例) -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

2. 核心配置(application.yml)

yaml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: 账号
    password: 密码
# MyBatis-Plus 配置
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # 开启下划线转驼峰(默认开启)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志
  global-config:
    db-config:
      id-type: auto # 全局主键自增策略

3. 核心注解(实体类映射)

表格

注解作用
@TableName("表名")实体类对应数据库表名
@TableId标记主键字段
@TableField("字段名")实体属性对应表字段
@TableField(exist = false)标记非数据库字段

示例实体类

@Data
@TableName("t_user") // 对应数据库表 t_user
public class User {
    @TableId(type = IdType.AUTO) // 主键自增
    private Long id;
    
    @TableField("user_name") // 对应表字段 user_name
    private String userName;
    
    private Integer age;
    
    @TableField(exist = false) // 数据库无此字段
    private String temp;
}

4. 核心 Mapper 接口(基础 CRUD)

继承 BaseMapper<T>无需写 XML,直接拥有单表 CRUD

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 无需编写方法,直接使用父类 CRUD
}

5. 基础 CRUD 方法

// 1. 新增
userMapper.insert(user);

// 2. 根据 ID 查询
User user = userMapper.selectById(1L);

// 3. 条件查询
List<User> list = userMapper.selectList(null); // 查询全部

// 4. 根据 ID 修改
userMapper.updateById(user);

// 5. 根据 ID 删除
userMapper.deleteById(1L);

二、中级进阶(条件构造器 + 分页 + 逻辑删除)

1. 强大的条件构造器 QueryWrapper/LambdaQueryWrapper

MP 核心功能,零 SQL 实现复杂条件查询,推荐用 LambdaQueryWrapper(防字段名写错)。

常用条件:

  • eq:等于
  • ne:不等于
  • gt:大于
  • ge:大于等于
  • lt:小于
  • le:小于等于
  • like:模糊查询
  • between:区间查询
  • orderByAsc/Desc:排序

示例

// Lambda 条件构造器(推荐)
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getAge, 20) // 年龄=20
       .like(User::getUserName, "张") // 用户名含"张"
       .between(User::getId, 1, 10) // ID 1-10
       .orderByDesc(User::getId); // 按 ID 降序

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

2. 分页查询(最完整实战版)

1)配置分页插件(SpringBoot)
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 防止全表溢出
        paginationInterceptor.setOverflow(true);
        // 最大单页限制
        paginationInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(paginationInterceptor);
        return interceptor;
    }
}
2)基础分页
// 第 1 页,每页 10 条
Page<User> page = new Page<>(1, 10);

// 条件
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getAge, 20);

// 执行
Page<User> result = userMapper.selectPage(page, wrapper);

// 结果
List<User> records = result.getRecords();    // 当前页数据
long total = result.getTotal();              // 总条数
long pages = result.getPages();              // 总页数
long current = result.getCurrent();          // 当前页
long size = result.getSize();                // 每页条数
3)VO 分页(最常用)
Page<UserVO> voPage = result.convert(user -> {
    UserVO vo = new UserVO();
    vo.setId(user.getId());
    vo.setName(user.getUserName());
    return vo;
});

3. 逻辑删除(企业必开)

作用:

  • 不真正删除数据,只做标记

  • 查询时自动过滤已删除数据

1)数据库加字段
ALTER TABLE t_user ADD COLUMN deleted TINYINT DEFAULT 0;
2)实体类标记
@TableLogic
private Integer deleted;
3)全局配置(推荐)
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted
      logic-delete-value: 1        # 已删除
      logic-not-delete-value: 0    # 未删除

效果

  • deleteById(1L) → 变成 UPDATE ... SET deleted=1
  • selectById(1L) → 自动拼接 AND deleted=0

4. 自动填充(create_time、update_time)

1)实体类
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
2)配置填充器
@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);
    }
}

效果

  • insert → 自动填 createTime、updateTime
  • update → 自动更新 updateTime

三、高级篇(企业级必备)

1. 批量操作(性能提升巨大)

MP 提供 IService 层,自带批量方法,比循环单条快 10~100 倍

1)定义 Service

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

2)常用批量方法

// 批量新增
userService.saveBatch(userList);

// 分批新增(推荐大数据量)
userService.saveBatch(userList, 1000);

// 批量修改
userService.updateBatchById(userList);

// 批量删除
userService.removeByIds(Arrays.asList(1L,2L,3L));

3)批量插入原理

  • 默认:拼一条 INSERT INTO ... VALUES (...),(...)
  • 大列表:自动分批,防止 SQL 过长

2. 多租户(Saas 系统必备)

作用

  • 一套数据库,多个公司 / 用户数据互相隔离
  • 所有 SQL 自动拼接 tenant_id = ?

1)添加租户插件

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

    // 多租户插件
    TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
    tenantInterceptor.setTenantLineHandler(new TenantLineHandler() {
        @Override
        public Expression getTenantId() {
            // 从登录信息获取租户ID
            Long tenantId = 10086L;
            return new LongValue(tenantId);
        }

        @Override
        public String getTenantIdColumn() {
            return "tenant_id"; // 租户字段
        }

        // 哪些表忽略租户
        @Override
        public boolean ignoreTable(String tableName) {
            return Arrays.asList("sys_dict").contains(tableName);
        }
    });

    interceptor.addInnerInterceptor(tenantInterceptor);
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    return interceptor;
}

效果

你写:

userMapper.selectList(null);

MP 自动生成:

SELECT * FROM t_user WHERE tenant_id = 10086 AND deleted = 0

3. 性能优化 & 最佳实践(面试高频)

1)禁止全表更新 / 删除(必开)

mybatis-plus:
  global-config:
    db-config:
      block-attack: true

作用:

  • update(user, null) → 直接报错
  • 防止线上事故

2)只查需要的字段

wrapper.select(User::getId, User::getUserName);

3)避免大量循环单条插入

坏的:

for (User user : list) {
    userMapper.insert(user);
}

userService.saveBatch(list, 1000);

4)SQL 性能分析插件

// 打印慢SQL
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100); // 超过100ms报警
performanceInterceptor.setFormat(true);
interceptor.addInnerInterceptor(performanceInterceptor);

5)枚举自动映射

@Getter
public enum StatusEnum {
    NORMAL(0, "正常"),
    DISABLE(1, "禁用");

    private final Integer code;
    private final String desc;
}
@TableField("status")
private StatusEnum status;

自动存 code,自动取转枚举。

6)乐观锁(防并发修改)

@Version
private Integer version;

更新时自动带 version = ?,版本不一致不更新。


四、总结(极简记忆版)

进阶

  1. 分页:配置插件 + new Page () + selectPage
  2. 逻辑删除:deleted 字段 + @TableLogic
  3. 自动填充:FieldFill + MetaObjectHandler

高级

  1. 批量操作:IService + saveBatch / updateBatchById
  2. 多租户:TenantLineInnerInterceptor,自动拼 tenant_id
  3. 性能优化:禁止全表更新、只查需要字段、批量、慢 SQL 监控

Logo

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

更多推荐