BaseMapper的介绍

BaseMapper 是什么?

它是 MyBatis‑Plus 提供的一个泛型接口 ,里面预定义了 CRUD 的 17 个常用方法。只要让你的 Mapper 继承它,无需编写 XML,即可实现单表的增删改查。


一、BaseMapper 接口源码概览(核心部分)

复制代码
public interface BaseMapper<T> extends Mapper<T> {

    // ===== 新增 =====
    int insert(T entity);

    // ===== 删除 =====
    int deleteById(Serializable id);
    int deleteByMap(@Param("cm") Map<String, Object> columnMap);
    int delete(@Param("ew") Wrapper<T> wrapper);
    int deleteBatchIds(@Param("coll") Collection<?> idList);

    // ===== 修改 =====
    int updateById(@Param("et") T entity);
    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

    // ===== 查询 =====
    T selectById(Serializable id);
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
    List<T> selectByMap(Map<String, Object> columnMap);
    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    // ===== 分页 =====
    <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);
}

二、环境准备:实体类(Entity)

在使用 BaseMapper 之前,必须先定义实体类,这是 MP 自动生成 SQL 的依据。

1️⃣ 实体类代码(逐行解释)

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

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

/**
 * @TableName("user")
 * 作用:指定该实体类对应的数据库表名。
 * 如果不写,MP 默认将类名驼峰转下划线(User -> user)。
 */
@TableName("user")
@Data // Lombok注解:自动生成 Getter、Setter、toString 等方法
public class User {

    /**
     * @TableId(type = IdType.AUTO)
     * 作用:标识该字段为主键,并指定主键生成策略。
     * IdType.AUTO:依赖数据库自增(如 MySQL 的 AUTO_INCREMENT)。
     * 如果是雪花算法,通常用 IdType.ASSIGN_ID。
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 普通字段
     * 变量名:username
     * 数据库列名:username(默认规则)
     */
    private String username;

    /**
     * 如果数据库字段名是 user_name,而属性名是 userName,
     * 需要加注解:@TableField("user_name")
     */
    private String password;

    /**
     * 注意:实体类不需要写任何方法,BaseMapper 会接管持久化操作。
     */
}

三、Mapper 层:继承 BaseMapper(核心步骤)

2️⃣ Mapper 接口代码(逐行解释)

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

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * UserMapper 接口
 * 作用:定义数据访问层(DAO层)的操作规范。
 */
@Mapper // 标记该类为 MyBatis 的 Mapper 接口,Spring 启动时会扫描并创建代理对象
public interface UserMapper extends BaseMapper<User> {

    /**
     * 重点解释:extends BaseMapper<User>
     *
     * 1. BaseMapper:MP 提供的通用 CRUD 接口。
     * 2. <User>:泛型,告诉 MP 这个 Mapper 是为 User 实体服务的。
     *
     * 继承后,UserMapper 瞬间拥有了 BaseMapper 里的所有方法:
     * - insert
     * - deleteById
     * - updateById
     * - selectById
     * - selectList
     * - ...等等
     *
     * 注意:这里不需要写任何方法体,也不需要写 XML。
     */

    // 如果有复杂的多表查询,可以在这里定义方法,然后在 XML 中实现
    // List<User> selectComplexUserList();
}

四、BaseMapper 方法实战(逐行拆解)

假设我们在测试类或 Service 中注入了 Mapper:

复制代码
@Autowired
private UserMapper userMapper;

3️⃣ 新增(Insert)

复制代码
@Test
public void testInsert() {
    User user = new User();
    user.setUsername("zhangsan");
    user.setPassword("123456");

    // 方法:insert(T entity)
    // 作用:将实体对象持久化到数据库。
    // 参数:user 实体对象。
    // 返回值:int(受影响的行数,成功通常为 1)。
    // 底层 SQL:INSERT INTO user (username, password) VALUES ('zhangsan', '123456');
    int rows = userMapper.insert(user);

    System.out.println("影响行数:" + rows);
    // 如果是自增主键,插入后 ID 会自动回填到 user 对象中
    System.out.println("插入后的ID:" + user.getId());
}

4️⃣ 删除(Delete)

复制代码
@Test
public void testDelete() {
    // 方法:deleteById(Serializable id)
    // 作用:根据主键 ID 删除记录。
    // 参数:主键的值(可以是 Integer、Long、String 等)。
    // 底层 SQL:DELETE FROM user WHERE id = 1;
    int rows = userMapper.deleteById(1L);
    System.out.println("删除行数:" + rows);
}

@Test
public void testDeleteBatch() {
    // 方法:deleteBatchIds(Collection<?> idList)
    // 作用:批量删除(根据 ID 集合)。
    // 参数:包含多个 ID 的集合(List、Set 等)。
    // 底层 SQL:DELETE FROM user WHERE id IN (1, 2, 3);
    List<Long> ids = Arrays.asList(2L, 3L, 4L);
    int rows = userMapper.deleteBatchIds(ids);
}

5️⃣ 修改(Update)

复制代码
@Test
public void testUpdate() {
    User user = new User();
    user.setId(5L); // 必须指定 ID,否则不知道改哪条
    user.setUsername("lisi_new");

    // 方法:updateById(T entity)
    // 作用:根据 ID 修改数据(非空字段才会被更新)。
    // 注意:MP 默认使用字段的 NULL 判断,如果字段为 null,则不出现在 SET 语句中。
    // 底层 SQL:UPDATE user SET username='lisi_new' WHERE id = 5;
    int rows = userMapper.updateById(user);
}

6️⃣ 查询(Select)

根据 ID 查询
复制代码
@Test
public void testSelectById() {
    // 方法:selectById(Serializable id)
    // 作用:根据主键查询一条记录。
    // 返回值:实体对象(查不到返回 null)。
    // 底层 SQL:SELECT id, username, password FROM user WHERE id = 5;
    User user = userMapper.selectById(5L);
    System.out.println(user);
}
查询全部(常用)
复制代码
@Test
public void testSelectList() {
    // 方法:selectList(Wrapper<T> queryWrapper)
    // 作用:查询列表。
    // 参数:条件构造器(Wrapper)。
    // 如果参数为 null,表示查询全部,无任何条件。
    // 底层 SQL:SELECT id, username, password FROM user;
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}
条件查询(Wrapper 初探)
复制代码
@Test
public void testSelectByCondition() {
    // QueryWrapper 是 MP 的条件构造器,用于拼接 WHERE 条件
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 拼接条件:username = 'zhangsan'
    wrapper.eq("username", "zhangsan");
    // 拼接条件:AND age > 18
    // wrapper.gt("age", 18);

    // 底层 SQL:SELECT * FROM user WHERE username = 'zhangsan';
    List<User> users = userMapper.selectList(wrapper);
}

7️⃣ 分页查询(重点)

注意:分页功能需要在配置类中注册拦截器才能生效(见附录)。

复制代码
@Test
public void testSelectPage() {
    // 1. 创建分页对象
    // Page(current, size): current 是当前页(从 1 开始),size 是每页条数
    Page<User> page = new Page<>(1, 5);

    // 2. 调用分页查询
    // 第一个参数是分页对象,第二个参数是条件构造器(null 表示无额外条件)
    Page<User> resultPage = userMapper.selectPage(page, null);

    // 3. 获取数据
    System.out.println("总记录数:" + resultPage.getTotal());
    System.out.println("总页数:" + resultPage.getPages());
    System.out.println("当前页数据:" + resultPage.getRecords());
}

五、BaseMapper 的执行原理(简图)

复制代码
Controller
   ↓
Service
   ↓
UserMapper (接口)
   ↓
MyBatis‑Plus 动态代理
   ↓
根据 User 实体 + 注解
   ↓
自动生成 SQL
   ↓
JDBC
   ↓
Database

六、BaseMapper 使用限制与注意事项

  1. 单表操作:BaseMapper 只能操作单张表,不支持多表 JOIN。

  2. 实体映射 :实体类必须存在,且最好标注 @TableName@TableId

  3. 主键策略 :如果数据库主键是自增的,实体类必须配置 IdType.AUTO,否则插入后拿不到 ID。

  4. Wrapper 注入风险selectList(null)会查询全表,数据量大时要慎用,必须加分页或条件。


七、附录:分页插件配置(必须配置才能用 selectPage)

复制代码
package com.example.demo.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 {

    /**
     * 添加分页拦截器
     * 作用:拦截 SQL,自动在 SQL 末尾拼接 LIMIT ? OFFSET ?
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件,指定数据库类型为 MySQL
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

八、总结口诀

实体映射表,Mapper 继承它。

增删改查全都有,条件构造 Wrapper。

单表 CRUD 不用写,分页记得加拦截。

相关推荐
caimouse1 小时前
Windows Research Kernel (WRK) 内存管理器完整分析
windows
孫治AllenSun1 小时前
【MDC】使用 MDC 封装一个 LogMdcUtil 工具类
java·spring boot·后端
vortex52 小时前
PowerShell Provider 机制详解:从文件系统到注册表的统一抽象
windows·powershell
plainGeekDev2 小时前
依赖管理 → Version Catalog
android·java·kotlin
淘源码d3 小时前
医学影像云PACS系统——PACS诊断工作站
java·源码·影像处理·医院管理系统·影像工作站·云pacs系统·dicom 标准通信
NiceCloud喜云4 小时前
Anthropic 一周三连发:Cowork 多端、Fable 5 按需付费、J-space 论文的技术解读
java·服务器·网络·人工智能·ai
SamDeepThinking4 小时前
组合还是继承?我在项目里主要看这两个判断
java·后端·面试
momo4 小时前
JAVA基础知识
java·开发语言
小狮子&4 小时前
ubuntu2604终端右键新建窗口
windows