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

相关推荐
mingo_敏14 分钟前
DeepAgents : 后端(Backends)
java·开发语言
霸道流氓气质16 分钟前
SpringBoot中事务内同步处理 + 事务后异步调用外部系统的通用模式示例
java·spring boot·后端
霸道流氓气质28 分钟前
Spring 事务传播机制与 REQUIRES_NEW
java·数据库·spring
luyun02020230 分钟前
论坛里的小工具,吾爱出品
运维·服务器·windows
BerryS3N40 分钟前
Java 后端转型大模型:Demo 能跑不等于能上线
java·人工智能·python·java后端·spring ai·langchain4j·大模型转型
心机之蛙qee44 分钟前
Docker Compose 多容器编排
java·docker·容器
秋田君1 小时前
QT_QColorDialog颜色对话框
java·数据库·qt
老王生涯2 小时前
rust开发环境配置-Windows & GNU
开发语言·windows·rust
nLif2 小时前
进程管道通讯-伪终端方式
c++·windows
用户91366296220122 小时前
ViewModelScope 简介与使用
java