一、前言
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) |
分页查询 |
四、核心注意事项
- 主键生成策略 :MP 默认使用雪花算法生成主键,若需使用自增主键,需在实体类
@TableId注解中指定type = IdType.AUTO,并确保数据库表主键设置为自增。 - 字段映射 :实体类字段名需与数据库表字段名一致(或通过
@TableField注解映射),否则会导致字段值为null。 - 批量操作限制 :
saveBatch默认每 1000 条数据分一次批,可通过saveBatch(users, 500)自定义批次大小。 - Wrapper 条件构造器 :
BaseMapper和IService的多数方法支持 Wrapper 参数,用于构建复杂查询条件,是 MP 的核心进阶功能。
五、总结
关键点回顾
BaseMapper是 MP 基础 CRUD 的核心,继承该接口即可无需编写 SQL 实现单表增删改查。- 通用
IService封装了更多业务层功能(如批量插入、统计总数),是BaseMapper的补充和增强。 - MP 的 CRUD 操作遵循 "面向对象" 思想,所有操作通过实体类完成,无需关注 SQL 编写,大幅提升开发效率。
通过本文的讲解,相信你已掌握 MP 的基础 CRUD 操作。后续将深入讲解条件构造器(Wrapper)、分页插件、逻辑删除等进阶功能,敬请关注!