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 不用写,分页记得加拦截。

相关推荐
2602_9599609215 小时前
大厂Java面试:Spring Boot、JVM、Redis、Kafka与Elasticsearch在内容社区UGC场景下的实战拷问
java·jvm·spring boot·redis·面试题
St_rive1 天前
Page Object设计模式
java·开发语言·设计模式
风流 少年1 天前
Spring AI 2.0:SSE
java·人工智能·spring
凤山老林1 天前
精细化流量治理:Spring Boot 动态特性开关与灰度发布体系
java·spring boot·后端
Aphelios3801 天前
一次锁内网络IO引发的Tomcat线程池“饿死”事故
java·开发语言·spring boot·elasticsearch·tomcat·网络io阻塞·线程池耗尽
不可求~1 天前
C++ std::string_view 不是字符串:从悬空引用到安全用法
java·开发语言·c++
Lam Tang1 天前
APS 系列文章10
java·代理模式
考虑考虑1 天前
Excel导入时产生特殊字符处理
java·后端·java ee
Scabbards_1 天前
面试Leetcode - Heap 堆
java·leetcode·面试
程序员清风1 天前
专业再升级!程序员专属显示器明基RD280UG上手实测!
java·后端·面试