MyBatis-Plus 超详细教程:从入门到实战,一站式掌握

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: MyBatis-Plus 是 MyBatis 的增强工具,简化单表 CRUD 操作,无需编写 XML,支持条件构造器、分页插件、逻辑删除、枚举与 JSON 处理,提升开发效率,兼顾灵活性与便捷性,助力从入门到实战一站式掌握。

在持久层框架体系中,MyBatis 凭借灵活的 SQL 控制能力成为主流,但单表 CRUD 仍需手写大量 XML 代码;Hibernate 侧重全自动化 ORM,但灵活性不足。而 MyBatis-Plus(简称 MP) 作为 MyBatis 的增强工具,在保留 MyBatis 原有优势的基础上,实现了单表 CRUD 零 XML 开发,大幅提升开发效率。本文将从入门到实战,全面讲解 MP 的核心功能与落地技巧。

一、快速入门:5 分钟搞定单表 CRUD

1.1 入门案例:告别重复 XML 代码

先看一个痛点:传统 MyBatis 实现单表增删改查,需要在 XML 中编写大量固定格式的 SQL(如 UserMapper.xml)。而 MP 可以彻底简化这一过程,核心步骤仅两步:

步骤 1:引入 MyBatis-Plus 起步依赖

MP 提供了官方 starter,集成 MyBatis 核心功能并实现自动装配,直接替换原有 MyBatis 依赖即可:

xml

<!-- 移除原有 MyBatis starter -->
<!-- <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.3.0</version>
</dependency> -->
<!-- 引入 MyBatis-Plus starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

步骤 2:继承 BaseMapper 接口

自定义 Mapper 接口继承 MP 提供的 BaseMapper,并指定实体类泛型,即可直接拥有单表 CRUD 能力:

java

运行

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
// 泛型指定对应实体类
public interface UserMapper extends BaseMapper<User> {
    // 无需手写任何方法,BaseMapper 已内置增删改查
}

快速替换原有 CRUD 代码

继承 BaseMapper 后,可直接调用内置方法实现以下功能,无需编写 XML:

功能 MP 调用方法
新增用户 userMapper.insert(user)
根据 ID 查询用户 userMapper.selectById(1L)
批量查询(ID 列表) userMapper.selectBatchIds(Arrays.asList(1L,2L))
根据 ID 更新用户 userMapper.updateById(user)
根据 ID 删除用户 userMapper.deleteById(1L)

改造完成后,原 UserMapper_20231023_150307.xml 中的 SQL 代码可全部删除,代码量大幅减少!

1.2 核心注解:解决表与实体的映射问题

MP 基于反射自动映射实体类与数据库表,但遇到「表名不一致、字段名不匹配」等场景时,需通过注解手动指定映射关系:

注解 作用 核心属性
@TableName 指定实体类对应的数据表名 value:表名
@TableId 指定主键字段 type:主键生成策略(如雪花算法)
@TableField 指定普通字段 value:字段名;exist:是否为数据库字段(false 表示非数据库字段)

示例:实体类映射配置

java

运行

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
// 实体类名与表名不一致时指定
@TableName("tb_user")
public class User {
    // 主键,使用雪花算法生成
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    
    // 字段名一致,可省略 @TableField
    private String username;
    
    // 字段名不一致(实体:userInfo → 数据库:info)
    @TableField("info")
    private String userInfo;
    
    // 非数据库字段,查询时忽略
    @TableField(exist = false)
    private String temp;
}

主键生成策略(IdType)说明

  • AUTO:数据库自增(需表主键设置自增);
  • INPUT:手动输入主键值;
  • ASSIGN_ID:MP 内置雪花算法生成 Long 类型主键(推荐);
  • ASSIGN_UUID:生成 UUID 主键。

1.3 核心配置:自定义 MP 行为

MP 配置继承 MyBatis 原生配置,可在 application.yml 中自定义规则:

yaml

mybatis-plus:
  type-aliases-package: com.itheima.mp.domain.po # 实体类别名扫描包
  mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper XML 路径(默认值)
  configuration:
    map-underscore-to-camel-case: true # 开启下划线 ↔ 驼峰自动映射(默认开启)
    cache-enabled: false # 关闭二级缓存
  global-config:
    db-config:
      id-type: assign_id # 全局主键策略:雪花算法
      update-strategy: not_null # 更新策略:只更新非空字段

二、核心功能:解锁 MP 高级用法

2.1 条件构造器:灵活组装 WHERE 条件

MP 提供 Wrapper 条件构造器,支持所有 SQL WHERE 条件语法,无需手写 SQL 即可实现复杂查询 / 更新。核心实现类:

  • QueryWrapper:用于查询场景,可指定返回字段;
  • UpdateWrapper:用于更新场景,可直接设置 SQL 片段。

案例 1:复杂条件查询

需求:查询用户名含「o」、余额 ≥ 1000 的用户,仅返回 id、username、info、balance 字段。

java

运行

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void testQueryWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                // 指定返回字段
                .select("id", "username", "info", "balance")
                // 模糊查询:username LIKE '%o%'
                .like("username", "o")
                // 大于等于:balance >= 1000
                .ge("balance", 1000);
        
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

案例 2:条件更新(QueryWrapper)

需求:将用户名「jack」的用户余额改为 2000。

java

运行

@Test
void testUpdateWithQueryWrapper() {
    // 1. 封装更新数据
    User user = new User();
    user.setBalance(2000);
    
    // 2. 封装更新条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .eq("username", "jack");
    
    // 3. 执行更新
    userMapper.update(user, wrapper);
}

案例 3:更新 SQL 片段(UpdateWrapper)

需求:将 id 为 1、2、4 的用户余额扣减 200(非直接赋值,需写 SQL 片段)。

java

运行

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import java.util.Arrays;
@Test
void testUpdateWrapper() {
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            // 设置 SQL 片段:balance = balance - 200
            .setSql("balance = balance - 200")
            // 条件:id IN (1,2,4)
            .in("id", Arrays.asList(1L, 2L, 4L));
    
    // 第一个参数传 null,更新逻辑由 wrapper 实现
    userMapper.update(null, wrapper);
}

2.2 自定义 SQL:结合 Wrapper 实现复杂逻辑

MP 支持「Wrapper 构建条件 + 自定义 SQL」,兼顾灵活性与简洁性。

需求:将 id 在指定范围的用户余额扣减指定值。

步骤 1:Mapper 接口定义方法

java

运行

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
public interface UserMapper extends BaseMapper<User> {
    // 注意:@Param("ew") 是固定名称,不可修改
    @Update("UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment}")
    void updateBalanceByIds(
            @Param("ew") LambdaQueryWrapper<User> wrapper,
            @Param("amount") int amount
    );
}

步骤 2:调用自定义方法

java

运行

@Test
void testCustomSqlWithWrapper() {
    // 1. 封装条件:id IN (1,2,4)
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
            .in(User::getId, Arrays.asList(1L, 2L, 4L));
    
    // 2. 执行自定义 SQL
    userMapper.updateBalanceByIds(wrapper, 200);
}

2.3 Service 层封装:更高效的 CRUD 工具

MP 为 Service 层提供 IServiceServiceImpl 封装,内置批量操作、分页查询等高频方法,比 BaseMapper 更易用。

步骤 1:定义 Service 接口与实现类

java

运行

// 1. Service 接口:继承 IService
public interface UserService extends IService<User> {
}
// 2. Service 实现类:继承 ServiceImpl,指定 Mapper 和实体类
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

案例 1:Lambda 条件查询

需求:根据用户名关键字、状态、余额范围查询用户(参数可为空)。

java

运行

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    public List<User> queryUserList(String name, Integer status, Integer minBalance, Integer maxBalance) {
        return lambdaQuery()
                // 条件:name 不为空时,模糊查询用户名
                .like(name != null, User::getUsername, name)
                // 条件:status 不为空时,精准匹配状态
                .eq(status != null, User::getStatus, status)
                // 条件:min/maxBalance 都不为空时,匹配余额范围
                .between(minBalance != null && maxBalance != null, User::getBalance, minBalance, maxBalance)
                .list();
    }
}

案例 2:Lambda 条件更新

需求:扣减用户余额,若扣减后余额为 0 则冻结用户(status=2)。

java

运行

public void updateUserBalance(Long id, String username, int amount) {
    lambdaUpdate()
            // 扣减余额
            .setSql("balance = balance - " + amount)
            // 余额为 0 时冻结
            .set(amount == 0, User::getStatus, 2)
            // 条件:id 和 username 不为空时匹配
            .eq(id != null, User::getId, id)
            .eq(username != null, User::getUsername, username)
            .update();
}

案例 3:批量新增(高性能)

需求:批量插入 10 万条用户数据(优化插入性能)。

  1. 首先在 JDBC 连接 URL 中添加参数(开启批处理优化):

yaml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_db?rewriteBatchedStatements=true
    username: root
    password: 123456
  1. 编写批量插入代码:

java

运行

public void batchSave() {
    // 1. 初始化 10 万条测试数据
    List<User> userList = new ArrayList<>(100000);
    for (int i = 0; i < 100000; i++) {
        User user = new User();
        user.setUsername("test_" + i);
        user.setBalance(100);
        userList.add(user);
    }
    
    // 2. MP 批量插入(默认每 1000 条批量提交)
    saveBatch(userList);
}

三、拓展功能:解决实际开发痛点

3.1 代码生成:一键生成 CRUD 代码

MP 支持通过插件 / 代码生成器一键生成 Entity、Mapper、Service、Controller 代码,彻底告别重复编码:

  1. 安装 IDEA 插件:MyBatisX(官方推荐);
  2. 配置数据库连接(Database 面板);
  3. 右键数据表 → MyBatisX-Generator → 配置生成规则 → 生成代码。

3.2 静态工具 Db:解决 Service 循环依赖

MP 提供静态工具类 Db,封装了 BaseMapper 核心方法,可直接调用,避免 Service 层相互注入导致的循环依赖:

java

运行

import com.baomidou.mybatisplus.extension.toolkit.Db;
import java.util.List;
// 直接查询 id 为 1 的用户
User user = Db.getById(1L, User.class);
// 批量查询
List<User> users = Db.listByIds(Arrays.asList(1L,2L), User.class);

3.3 逻辑删除:避免物理删除数据

逻辑删除通过「标记字段」模拟删除效果(不真正删除数据),MP 可自动拦截 CRUD 操作:

步骤 1:配置逻辑删除(application.yml)

yaml

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 逻辑删除字段名
      logic-delete-value: 1 # 已删除标记
      logic-not-delete-value: 0 # 未删除标记

步骤 2:实体类添加字段

java

运行

@TableField("deleted")
private Integer deleted; // 0:未删除,1:已删除

配置完成后:

  • 调用 deleteById(1L) 时,MP 自动执行 UPDATE tb_user SET deleted=1 WHERE id=1
  • 调用 selectList() 时,MP 自动添加条件 WHERE deleted=0

⚠️ 注意:逻辑删除会产生大量「垃圾数据」,需定期清理或迁移至历史表。

3.4 枚举处理器:实现枚举与数据库字段映射

数据库中状态字段(如 status)通常用 int 存储,实体类中用枚举更易读,MP 可通过注解实现自动映射:

步骤 1:枚举类添加注解

java

运行

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结");
    // 标记与数据库对应的数值
    @EnumValue
    private final int value;
    private final String desc;
    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

步骤 2:配置全局枚举处理器

yaml

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

步骤 3:实体类使用枚举

java

运行

private UserStatus status; // 自动映射:1 → NORMAL,2 → FREEZE

3.5 JSON 处理器:支持 JSON 类型字段

数据库中 JSON 类型字段(如 info),MP 可通过注解自动序列化 / 反序列化为实体类属性:

java

运行

import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.baomidou.mybatisplus.annotation.TableField;
// 数据库 info 字段为 JSON 类型,自动映射为 UserInfo 对象
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
// 嵌套 JSON 实体
@Data
public class UserInfo {
    private Integer age;
    private String gender;
    private String intro;
}

四、插件功能:分页插件(高频使用)

MP 提供内置拦截器插件,其中「分页插件」是开发中最常用的功能,支持物理分页。

4.1 配置分页插件

java

运行

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();
        // 添加分页插件(指定数据库类型)
        PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
        pageInterceptor.setDbType(com.baomidou.mybatisplus.annotation.DbType.MYSQL);
        pageInterceptor.setMaxLimit(1000L); // 限制最大分页条数(防止性能问题)
        interceptor.addInnerInterceptor(pageInterceptor);
        return interceptor;
    }
}

4.2 分页查询实战

java

运行

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.jupiter.api.Test;
@Test
void testPageQuery() {
    // 1. 分页参数:第 1 页,每页 5 条
    Page<User> page = Page.of(1, 5);
    
    // 2. 排序参数:按 balance 降序
    page.addOrder(new OrderItem("balance", false));
    
    // 3. 执行分页查询(Service 层)
    Page<User> resultPage = userService.page(page);
    
    // 4. 获取分页结果
    System.out.println("总条数:" + resultPage.getTotal());
    System.out.println("总页数:" + resultPage.getPages());
    System.out.println("当前页数据:" + resultPage.getRecords());
}

4.3 通用分页接口:标准化分页返回

实际开发中,分页接口需统一入参和出参格式,以下是通用实现方案:

步骤 1:定义分页入参(PageQuery)

java

运行

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
@Data
public class PageQuery {
    private Integer pageNo = 1; // 默认第 1 页
    private Integer pageSize = 10; // 默认每页 10 条
    private String sortBy; // 排序字段
    private Boolean isAsc = true; // 是否升序
    // 转换为 MP 分页对象(默认按 update_time 降序)
    public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {
        return toMpPage("update_time", false);
    }
    // 转换为 MP 分页对象(自定义默认排序)
    public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) {
        Page<T> page = Page.of(pageNo, pageSize);
        // 前端传了排序字段则用前端的,否则用默认
        if (sortBy != null) {
            page.addOrder(new OrderItem(sortBy, isAsc));
        } else {
            page.addOrder(new OrderItem(defaultSortBy, isAsc));
        }
        return page;
    }
}

步骤 2:定义分页出参(PageDTO)

java

运行

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.hutool.core.bean.BeanUtil;
import lombok.Data;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Data
public class PageDTO<V> {
    private Long total; // 总条数
    private Long pages; // 总页数
    private List<V> list; // 当前页数据
    // 空结果封装
    public static <V, P> PageDTO<V> empty(Page<P> page) {
        return new PageDTO<>(page.getTotal(), page.getPages(), Collections.emptyList());
    }
    // PO 转 VO(自动拷贝)
    public static <V, P> PageDTO<V> of(Page<P> page, Class<V> voClass) {
        List<P> records = page.getRecords();
        if (records.isEmpty()) {
            return empty(page);
        }
        List<V> voList = BeanUtil.copyToList(records, voClass);
        return new PageDTO<>(page.getTotal(), page.getPages(), voList);
    }
    // 自定义 PO 转 VO 逻辑
    public static <V, P> PageDTO<V> of(Page<P> page, Function<P, V> convertor) {
        List<P> records = page.getRecords();
        if (records.isEmpty()) {
            return empty(page);
        }
        List<V> voList = records.stream().map(convertor).collect(Collectors.toList());
        return new PageDTO<>(page.getTotal(), page.getPages(), voList);
    }
}

步骤 3:编写分页接口

java

运行

// 1. Controller 层
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/page")
    public PageDTO<UserVO> queryUserByPage(PageQuery query) {
        return userService.queryUserByPage(query);
    }
}
// 2. Service 层实现
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Override
    public PageDTO<UserVO> queryUserByPage(PageQuery query) {
        // 1. 构建分页条件(默认按 update_time 降序)
        Page<User> page = query.toMpPageDefaultSortByUpdateTimeDesc();
        
        // 2. 执行分页查询(可叠加 Lambda 条件)
        page(page, lambdaQuery().eq(User::getStatus, 1));
        
        // 3. 转换为 VO 并返回
        return PageDTO.of(page, UserVO.class);
    }
}

接口测试

访问地址:http://localhost:8080/users/page?pageNo=1&pageSize=5&sortBy=balance&isAsc=false

返回结果示例:

json

{
  "total": 1005,
  "pages": 201,
  "list": [
    {
      "id": 1,
      "username": "Jack",
      "info": "{\"age\":21,\"gender\":\"male\",\"intro\":\"佛系青年\"}",
      "status": 1,
      "balance": 2000
    }
  ]
}

五、总结

MyBatis-Plus 作为 MyBatis 的增强工具,核心优势是「简化单表 CRUD、保留自定义 SQL 灵活性」:

  1. 基础层:BaseMapper + IService 实现零 XML 单表操作;
  2. 进阶层:Wrapper 条件构造器实现复杂 WHERE 条件;
  3. 拓展层:逻辑删除、枚举 / JSON 处理器解决实际开发痛点;
  4. 插件层:分页插件是高频必备功能,需熟练掌握。

掌握 MP 可大幅减少重复编码,提升开发效率,是后端开发者必备技能!

相关文章
|
JavaScript 前端开发 Java
基于SpringBoot+Vue实现前后端交互功能(详解Vue框架机制)
基于SpringBoot+Vue实现前后端交互功能(详解Vue框架机制)
|
6月前
|
SQL Java 数据库连接
MyBatis升级版:MyBatisPlus
MyBatisPlus是MyBatis的增强工具,简化单表CRUD操作,无需编写XML即可实现增删改查。通过继承BaseMapper、使用条件构造器(如QueryWrapper)、Service接口及分页插件,大幅提升开发效率。支持自定义SQL、逻辑删除、枚举与JSON处理,并提供代码生成器和通用分页封装,广泛应用于企业级项目中。
|
SQL 缓存 Java
【吐血整理】MyBatis从入门到精通
本文介绍了 MyBatis 的使用指南,涵盖开发环境搭建、基础操作实例和进阶特性。首先,详细描述了 JDK 和 IDE 的安装及依赖引入,确保项目顺利运行。接着,通过创建用户表和实体类,演示了 CRUD 操作的全流程,包括查询、插入、更新和删除。最后,深入探讨了动态 SQL 和缓存机制等高级功能,帮助开发者提升数据库交互效率和代码灵活性。掌握这些内容,能显著提高 Java 编程中的数据库操作能力。
2036 4
|
2月前
|
JSON 前端开发 Java
【注解】@RequestBody与@ResponseBody 全方位对比全解
本文全方位解析Spring中`@RequestBody`与`@ResponseBody`:从`HttpMessageConverter`底层机制、数据流向(入站反序列化 vs 出站序列化)、使用限制、组合实践(`@RestController`)、配置技巧到高频踩坑,助你深入掌握RESTful接口开发核心。
|
2月前
|
SQL Java 数据库连接
SpringBoot整合MyBatis-Flex保姆级教程,看完就能上手!
MyBatis-Flex 作为一个现代化的 MyBatis 增强框架,在保持 MyBatis 灵活性的同时,提供了更多便捷的功能,特别适合需要复杂查询和高性能要求的项目。
373 0
|
6月前
|
XML 监控 Java
为什么学习 Spring Boot?—— 从官方定位、核心优势到未来趋势全面解析
Spring Boot 是 Java 后端开发的事实标准,凭借“开箱即用”、Starter 依赖、简化配置、内嵌容器和 Actuator 监控等五大优势,成为构建微服务的核心框架。官方定位“Build Anything”,助力开发者高效构建现代化应用,是通往云原生时代的必备技能。
|
6月前
|
消息中间件 缓存 NoSQL
【Redis进阶】不止是缓存!Redis的5种核心数据结构与实战场景全解析
本文深入浅出地解析了Redis五大核心数据结构:String、Hash、List、Set和ZSet,结合图解与实战场景,涵盖缓存、计数器、分布式锁、购物车、消息队列、排行榜等典型应用,助你摆脱“只会SET/GET”的困境,真正发挥Redis的高性能潜力。
|
6月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
MyBatisPlus是MyBatis的增强框架,简化单表CRUD操作,内置分页、条件构造器、代码生成等功能,支持逻辑删除、枚举处理与JSON字段映射,提升开发效率。
|
SQL Java 数据库连接
MyBatis-Plus:简化 CRUD 操作的艺术
MyBatis-Plus 是一个基于 MyBatis 的增强工具,它旨在简化 MyBatis 的使用,提高开发效率。
903 1
MyBatis-Plus:简化 CRUD 操作的艺术