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 使用限制与注意事项
-
单表操作:BaseMapper 只能操作单张表,不支持多表 JOIN。
-
实体映射 :实体类必须存在,且最好标注
@TableName和@TableId。 -
主键策略 :如果数据库主键是自增的,实体类必须配置
IdType.AUTO,否则插入后拿不到 ID。 -
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 不用写,分页记得加拦截。