Mybatis-Plus:让CRUD快如闪电

一、引言

在 SpringBoot 开发中,Mybatis 一直是国内最流行的持久层框架。但它有个让人头疼的地方:每写一个简单的增删改查,都要去 XML 或注解里手写一遍 SQL,即使只是 select * from user where id = ? 这种毫无技术含量的语句。

Mybatis-Plus(简称 MP)就是为「干掉重复的简单 SQL」而生的。它在 Mybatis 的基础上只做增强、不做改变,能让我们用极少量的代码完成绝大多数 CRUD 操作。本文就从零带你上手 Mybatis-Plus。

二、Mybatis-Plus 是什么

Mybatis-Plus 是一个 Mybatis 的增强工具,由国人开发(作者「青苗」),目前已经是国内使用最广的 ORM 增强框架之一。核心思想:在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

它提供了以下核心能力:

  • 通用 BaseMapper:内置单表的增删改查,无需写任何 SQL;
  • 强大的条件构造器:QueryWrapper / LambdaQueryWrapper 链式拼条件;
  • 内置分页插件;
  • 代码生成器、逻辑删除、乐观锁、自动填充等开箱即用的功能。

三、相比原生 Mybatis 的优势

对比项 原生 Mybatis Mybatis-Plus
简单 CRUD 需手写 SQL 或注解 BaseMapper 一键搞定
分页 需引入 PageHelper 或手写 内置分页插件
条件拼接 动态 SQL 手写 <if> 等 条件构造器链式调用
字段名书写 字符串易写错 Lambda 方式类型安全
代码量 大 小

一句话总结:**原生 Mybatis 该有的能力它全保留,繁琐的简单 CRUD 它全替你做了。**​

四、快速上手:集成 SpringBoot

4.1 引入依赖

本文使用 SpringBoot 3.x,Mybatis-Plus 需使用 mybatis-plus-spring-boot3-starter:

xml

复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- 简化实体类,非必须,但强烈推荐 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

注意:如果是 SpringBoot 2.x,请使用 mybatis-plus-boot-starter。

4.2 配置数据源

application.yml:

yaml

复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  configuration:
    # 控制台打印 SQL,方便调试
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: auto   # 主键自增

4.3 准备数据表

sql

复制代码
CREATE DATABASE IF NOT EXISTS mp_demo DEFAULT CHARACTER SET utf8mb4;
USE mp_demo;

CREATE TABLE `user` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` VARCHAR(50) DEFAULT NULL COMMENT '姓名',
  `age` INT DEFAULT NULL COMMENT '年龄',
  `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

4.4 实体类 User

java

复制代码
package com.example.mp.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@TableName("user")   // 指定对应表名(类名与表名不一致时必填)
public class User {

    @TableId(type = IdType.AUTO)  // 主键自增
    private Long id;

    private String name;

    private Integer age;

    private String email;

    private LocalDateTime createTime;
}

4.5 Mapper 接口

java

复制代码
package com.example.mp.mapper;

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 已经全部内置,这里可以什么都不写
}

启动类记得加 @MapperScan(或每个 Mapper 上手动加 @Mapper,二选一):

java

复制代码
package com.example.mp;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.mp.mapper")
public class MpDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MpDemoApplication.class, args);
    }
}

五、BaseMapper 通用 CRUD

继承 BaseMapper 后,我们就白拿了大量通用方法。看一个完整的 Service 示例:

java

复制代码
package com.example.mp.service;

import com.example.mp.entity.User;
import com.example.mp.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    /** 增:插入一条记录 */
    public void insert() {
        User user = new User();
        user.setName("张三");
        user.setAge(20);
        user.setEmail("zhangsan@example.com");
        user.setCreateTime(LocalDateTime.now());
        userMapper.insert(user);
        // 插入成功后,自增主键会自动回填到 user.getId()
        System.out.println("插入成功,主键 = " + user.getId());
    }

    /** 删:按主键删 / 批量删 */
    public void delete() {
        userMapper.deleteById(1L);                          // 按主键删除
        userMapper.deleteBatchIds(Arrays.asList(2L, 3L));   // 按主键批量删除
    }

    /** 改:按主键更新(只更新非 null 字段) */
    public void update() {
        User user = new User();
        user.setId(1L);
        user.setAge(30);   // 只更新 age 字段,其余字段为 null 不会被更新
        userMapper.updateById(user);
    }

    /** 查:按主键查 / 批量查 / 查所有 */
    public void select() {
        User user = userMapper.selectById(1L);
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
        List<User> all = userMapper.selectList(null);  // 传 null 表示无条件,查全部
        long count = userMapper.selectCount(null);     // 查总数
    }
}

BaseMapper 还提供了 insertBatch、update、selectPage、selectOne 等数十个方法,覆盖了绝大多数单表操作场景。

六、条件构造器:QueryWrapper 与 LambdaQueryWrapper

当查询条件变复杂时,就需要条件构造器登场了。

java

复制代码
package com.example.mp.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mp.entity.User;
import com.example.mp.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class WrapperDemoService {

    @Autowired
    private UserMapper userMapper;

    public void queryWrapperDemo() {
        // 方式一:QueryWrapper ------ 字段名以字符串形式书写
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("age", 20)                 // age = 20
          .like("name", "张")            // name LIKE '%张%'
          .between("age", 18, 30)        // age BETWEEN 18 AND 30
          .orderByDesc("id");            // ORDER BY id DESC
        List<User> list1 = userMapper.selectList(qw);

        // 方式二:LambdaQueryWrapper ------ 基于 Lambda,类型安全,字段名不会写错
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getAge, 20)
           .like(User::getName, "张")
           .between(User::getAge, 18, 30)
           .orderByDesc(User::getId);
        List<User> list2 = userMapper.selectList(lqw);
    }
}

常用条件方法速查:

方法 含义 示例
eq 等于 = eq("age", 20)
ne 不等于 != ne("age", 20)
gt / ge 大于 / 大于等于 gt("age", 18)
lt / le 小于 / 小于等于 le("age", 30)
like / likeLeft / likeRight 模糊匹配 like("name", "张")
between 区间 between("age", 18, 30)
in 集合 in("id", 1, 2, 3)
isNull / isNotNull 判空 isNull("email")
orderByAsc / orderByDesc 排序 orderByDesc("id")

推荐日常使用 LambdaQueryWrapper:一旦字段名重命名,编译器会直接报错,避免运行时才暴露的字符串拼写问题。

七、分页插件配置

Mybatis-Plus 的分页需要先注册一个插件,非常轻量。

配置类:

java

复制代码
package com.example.mp.config;

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;
    }
}

使用示例:

java

复制代码
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mp.entity.User;
import com.example.mp.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PageDemoService {

    @Autowired
    private UserMapper userMapper;

    public void pageDemo() {
        Page<User> page = new Page<>(1, 5);  // 第 1 页,每页 5 条
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.orderByDesc(User::getId);
        Page<User> result = userMapper.selectPage(page, lqw);

        System.out.println("总记录数:" + result.getTotal());
        System.out.println("总页数:" + result.getPages());
        System.out.println("当前页数据:" + result.getRecords());
    }
}

八、总结

Mybatis-Plus 的价值可以概括为一句话:它让「写 SQL」这件事从每天必做,变成了只有复杂场景才需要做的事。

本文我们完成了:

  1. 认识了 Mybatis-Plus 及它相对原生 Mybatis 的优势;
  2. 完成了 SpringBoot 集成(依赖、配置、实体、Mapper);
  3. 用 BaseMapper 实现了零 SQL 的通用 CRUD;
  4. 用 QueryWrapper / LambdaQueryWrapper 拼复杂条件;
  5. 配置并使用了内置分页插件。

掌握这些,日常单表开发基本可以告别手写 SQL 了。

相关推荐
paopaokaka_luck1 小时前
个人综合管理小程序(echarts数据看板、健康数据记录与趋势查看、目标拆解和进度管理、日程待办与番茄钟、习惯打卡、收支统计、个人生活记录、跨模块智能提醒)
前端·javascript·spring·小程序·数据分析·echarts·生活
盐焗鹌鹑蛋1 小时前
【Linux】线程概念和控制
java·linux·服务器
CarIise1 小时前
MyBatis缓存与分页插件:从一级二级缓存到底层原理与PageHelper实战
java·开发语言·spring
宸津-代码粉碎机8 小时前
OpenAI 连夜迎战 Grok Bot 和 Muse:AI 智能体从 “会聊天” 到 “能办事”,现在入场还来得及吗
java·大数据·人工智能·分布式·python
噢,我明白了9 小时前
java中唯一键和幂等键的应用
java·后端
程序猿乐锅9 小时前
【黑马点评 | 第八篇】Redisson分布式锁
java·数据库·spring boot·redis·分布式·spring·缓存
考虑考虑9 小时前
synchronized字符串常量
java·后端·java ee
长谷深风1119 小时前
Tool与Skill:AI能力设计的分水岭
java·人工智能·ai·大模型·aiagent
m0_587383009 小时前
广州24小时自助健身房解决方案实战指南与系统部署要点
java·spring·小程序·架构·需求分析