MyBatis-Plus 核心 CRUD 操作全解析:BaseMapper 与通用 Service 实战

一、前言

MyBatis-Plus(简称 MP)的核心优势之一就是无需编写任何 SQL 即可实现单表的增删改查(CRUD)操作,其底层通过内置的BaseMapper接口封装了所有基础 CRUD 方法,同时提供IService通用服务层进一步简化业务逻辑开发。本文将从实战角度,详细讲解BaseMapper的所有 CRUD 方法使用方式,以及通用 Service 的进阶用法,帮助开发者快速掌握 MP 的核心操作。

二、BaseMapper:基础 CRUD 的核心实现

BaseMapper<T>是 MP 为单表 CRUD 提供的核心接口,泛型T为操作的实体类,所有继承该接口的 Mapper 无需编写任何方法,即可直接使用内置的 CRUD 功能。

2.1 BaseMapper 核心接口定义

java 复制代码
package com.baomidou.mybatisplus.core.mapper;
public interface BaseMapper<T> extends Mapper<T> {
    /**
     * 插入一条记录
     * @param entity 实体对象
     */
    int insert(T entity);

    /**
     * 根据 ID 删除
     * @param id 主键ID
     */
    int deleteById(Serializable id);

    /**
     * 根据实体(ID)删除
     * @param entity 实体对象
     * @since 3.4.4
     */
    int deleteById(T entity);

    /**
     * 根据 columnMap 条件,删除记录
     * @param columnMap 表字段 map 对象
     */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * 根据 entity 条件,删除记录
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 删除(根据ID 批量删除)
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * 根据 ID 修改
     * @param entity 实体对象
     */
    int updateById(@Param(Constants.ENTITY) T entity);

    /**
     * 根据 whereEntity 条件,更新记录
     * @param entity        实体对象 (set 条件值)
     * @param updateWrapper 实体对象封装操作类(可以为 null)
     */
    int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * 根据 ID 查询
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * 查询(根据ID 批量查询)
     * @param idList 主键ID列表
     */
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * 查询(根据 columnMap 条件)
     * @param columnMap 表字段 map 对象
     */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * 根据 entity 条件,查询一条记录
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
        List<T> ts = this.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(ts)) {
            if (ts.size() != 1) {
                throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");
            }
            return ts.get(0);
        }
        return null;
    }

    /**
     * 根据 Wrapper 条件,查询总记录数
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 entity 条件,查询全部记录
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件,查询全部记录(返回Map)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件,查询全部记录(只返回第一个字段)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 entity 条件,查询全部记录(并翻页)
     * @param page 分页查询条件
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    <P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件,查询全部记录(并翻页,返回Map)
     * @param page 分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
 

2.2 BaseMapper 实战:增删改查

1. 新增(insert)

MP 默认采用雪花算法生成主键 ID,插入数据时无需手动设置 ID。

java 复制代码
@Test
public void testInsert(){
    // 实体对象:id为null,由MP自动生成
    User user = new User(null, "张三", 23, "zhangsan@qcby.com");
    // 执行SQL:INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
    int result = userMapper.insert(user);
    System.out.println("受影响行数:"+result); // 输出:1
    System.out.println("id自动获取:"+user.getId()); // 输出类似:1475754982694199298
}
2. 删除(delete)

MP 提供 4 种删除方式,满足不同场景需求:

(1)根据 ID 删除
java 复制代码
@Test
public void testDeleteById(){
    // 执行SQL:DELETE FROM user WHERE id=?
    int result = userMapper.deleteById(1475754982694199298L);
    System.out.println("受影响行数:"+result); // 输出:1
}
(2)批量 ID 删除
java 复制代码
@Test
public void testDeleteBatchIds(){
    // 构建ID列表
    List<Long> idList = Arrays.asList(1L, 2L, 3L);
    // 执行SQL:DELETE FROM user WHERE id IN ( ? , ? , ? )
    int result = userMapper.deleteBatchIds(idList);
    System.out.println("受影响行数:"+result); // 输出:3
}
(3)根据 Map 条件删除

Map 的 key 为数据库字段名,value 为字段值,多条件默认是AND关系。

java 复制代码
@Test
public void testDeleteByMap(){
    Map<String, Object> map = new HashMap<>();
    map.put("age", 23);
    map.put("name", "张三");
    // 执行SQL:DELETE FROM user WHERE name = ? AND age = ?
    int result = userMapper.deleteByMap(map);
    System.out.println("受影响行数:"+result); // 输出:1
}
(4)条件构造器删除(Wrapper)

适用于复杂条件删除,后续单独讲解 Wrapper 用法。

3. 修改(update)
(1)根据 ID 修改

仅修改实体中不为null的字段。

java 复制代码
@Test
public void testUpdateById(){
    // 仅修改name和age,email为null不参与更新
    User user = new User(4L, "admin", 22, null);
    // 执行SQL:UPDATE user SET name=?, age=? WHERE id=?
    int result = userMapper.updateById(user);
    System.out.println("受影响行数:"+result); // 输出:1
}
(2)条件构造器修改

适用于多条件批量修改,后续讲解。

4. 查询(select)
(1)根据 ID 查询
java 复制代码
@Test
public void testSelectById(){
    // 执行SQL:SELECT id,name,age,email FROM user WHERE id=?
    User user = userMapper.selectById(4L);
    System.out.println(user); // 输出:User(id=4, name=admin, age=22, email=null)
}
(2)批量 ID 查询
java 复制代码
@Test
public void testSelectBatchIds(){
    List<Long> idList = Arrays.asList(4L,5L);
    // 执行SQL:SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
    List<User> list = userMapper.selectBatchIds(idList);
    list.forEach(System.out::println);
}
(3)根据 Map 条件查询
java 复制代码
@Test
public void testSelectByMap(){
    Map<String, Object> map = new HashMap<>();
    map.put("age", 22);
    map.put("name", "admin");
    // 执行SQL:SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
    List<User> list = userMapper.selectByMap(map);
    list.forEach(System.out::println);
}
(4)查询所有数据

将 Wrapper 参数设为null,即可查询全表数据:

java 复制代码
@Test
public void testSelectList(){
    // 执行SQL:SELECT id,name,age,email FROM user
    List<User> list = userMapper.selectList(null);
    list.forEach(System.out::println);
}

三、通用 Service:业务层的进阶封装

MP 在BaseMapper基础上,封装了IService接口和ServiceImpl实现类,提供了更多业务层常用功能(如批量插入、统计记录数等),进一步简化开发。

3.1 核心说明

  • IService:通用 Service 接口,封装了 CRUD 操作,采用get(单行查询)、remove(删除)、list(集合查询)、page(分页)等前缀命名,避免与 Mapper 层混淆。
  • ServiceImpl<M extends BaseMapper<T>, T>IService的默认实现类,需传入 Mapper 和实体类泛型。

3.2 实战步骤

1. 创建 Service 接口
java 复制代码
/**
 * UserService继承IService,获取基础CRUD功能
 */
public interface UserService extends IService<User> {
    // 可自定义业务方法
}
2. 创建 Service 实现类
java 复制代码
/**
 * 继承ServiceImpl,指定Mapper和实体类
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    // 无需编写基础方法,直接使用父类实现
}

3.3 通用 Service 核心用法

1. 查询记录总数
java 复制代码
@Test
public void testCount(){
    // 执行SQL:SELECT COUNT(*) FROM user
    long count = userService.count();
    System.out.println("总记录数:"+count); // 输出全表记录数
}
2. 批量插入

注意 :批量插入功能在IService中实现(而非BaseMapper),因为 SQL 长度有限制,海量数据插入需分批次执行。

java 复制代码
@Test
public void testSaveBatch(){
    ArrayList<User> users = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        User user = new User();
        user.setName("szy" + i);
        user.setAge(20 + i);
        users.add(user);
    }
    // 执行SQL:INSERT INTO user ( name, age ) VALUES ( ?, ? )(分批次插入)
    userService.saveBatch(users);
}
3. 其他常用方法
方法名 功能描述
save(T entity) 新增单条数据
removeById(Serializable id) 根据 ID 删除
updateById(T entity) 根据 ID 更新
getById(Serializable id) 根据 ID 查询
list() 查询所有数据
page(Page<T> page) 分页查询

四、核心注意事项

  1. 主键生成策略 :MP 默认使用雪花算法生成主键,若需使用自增主键,需在实体类@TableId注解中指定type = IdType.AUTO,并确保数据库表主键设置为自增。
  2. 字段映射 :实体类字段名需与数据库表字段名一致(或通过@TableField注解映射),否则会导致字段值为null
  3. 批量操作限制saveBatch默认每 1000 条数据分一次批,可通过saveBatch(users, 500)自定义批次大小。
  4. Wrapper 条件构造器BaseMapperIService的多数方法支持 Wrapper 参数,用于构建复杂查询条件,是 MP 的核心进阶功能。

五、总结

关键点回顾

  1. BaseMapper是 MP 基础 CRUD 的核心,继承该接口即可无需编写 SQL 实现单表增删改查。
  2. 通用IService封装了更多业务层功能(如批量插入、统计总数),是BaseMapper的补充和增强。
  3. MP 的 CRUD 操作遵循 "面向对象" 思想,所有操作通过实体类完成,无需关注 SQL 编写,大幅提升开发效率。

通过本文的讲解,相信你已掌握 MP 的基础 CRUD 操作。后续将深入讲解条件构造器(Wrapper)、分页插件、逻辑删除等进阶功能,敬请关注!

相关推荐
开开心心就好1 小时前
一键加密隐藏视频,专属格式播放工具
java·linux·开发语言·网络·人工智能·macos
Amarantine、沐风倩✨2 小时前
列表接口严禁嵌套 LISTAGG + REGEXP:一次 mission_label 性能事故复盘
java·数据库·sql
好好研究2 小时前
MyBatis - Plus(二)常见注解 + 常见配置
数据库·spring boot·mybatis·mybatis plus
CUC-MenG2 小时前
Codeforces Round 1079 (Div. 2)A,B,C,D,E1,E2,F个人题解
c语言·开发语言·数学·算法
阿里嘎多学长2 小时前
2026-02-07 GitHub 热点项目精选
开发语言·程序员·github·代码托管
m***06682 小时前
Java进阶(ElasticSearch的安装与使用)
java·elasticsearch·jenkins
Anastasiozzzz2 小时前
Java异步编程:CompletableFuture从入门到底层实现
java·开发语言
xiaomin-Michael2 小时前
netty学习
java
九.九3 小时前
高性能算子库 ops-nn 的底层架构:从调度到指令的极致优化
开发语言