目录
[4 IService](#4 IService)
[4.1 概述](#4.1 概述)
[4.2 创建接口和实现类](#4.2 创建接口和实现类)
[4.3 IService接口里的方法](#4.3 IService接口里的方法)
[4.3.1 新增](#4.3.1 新增)
4 IService
4.1 概述
- MyBatisPlus 对 Service 层 CRUD 操作进行通用封装,提供 IService 接口和其实现类 ServiceImpl作为核心封装载体,里面的 CRUD 方法命名使用同一的规范。
- IService方法命名规则:CRUD 方法采用特定前缀区分,避免与 Mapper 层混淆 ------get 对应单行查询、remove 对应删除操作、list 对应集合查询、page 对应分页查询。
- 泛型设计:IService 接口支持泛型 ,T 可指代任意实体对象,适配不同数据表的 CRUD 需求。
- 进阶建议:若项目存在自定义通用 Service 方法的需求(非 MP 自带 CRUD),可以自己创建一个 IBaseService 接口(叫什么随意),且该接口需继承 MyBatis-Plus 提供的 IService 基类,实现通用方法的统一管理与复用。
- 底层原理:IService 利用 Java 8 默认方法特性(具体见++10 jdk1.8新功能++),为多数 CRUD 方法提供预先实现;MyBatisPlus 同时提供 ServiceImpl 实现类,其核心职责是持有并注入 Mapper 实例、提供 getBaseMapper() 方法(供 IService 默认方法调用 Mapper 层操作),还会显式实现部分复杂方法(如 saveOrUpdate)。
- 使用方式:自定义 Service 接口(如 UserService)需继承 IService,自定义 Service 实现类(如 UserServiceImpl)需继承 ServiceImpl<具体Mapper, T> 并实现自定义 Service 接口,即可直接复用 IService 中的所有通用 CRUD 方法,无需手动编写重复逻辑。
- 参考资料:官方文档地址为 https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3。
4.2 创建接口和实现类
package com.qcby.mybatisplus1122.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qcby.mybatisplus1122.entity.User;
/**
* UserService继承IService模板提供的基础功能
*/
public interface UserService extends IService<User> {
}
注:IService 的 T 必须和对应的 BaseMapper 的 T 一致。这是因为 IService 的通用方法最终会调用 BaseMapper 的方法,若类型不匹配,Mapper 层无法识别 Service 层传递的类型,导致数据库操作的表与实体不对应。
package com.qcby.mybatisplus1122.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcby.mybatisplus1122.entity.User;
import com.qcby.mybatisplus1122.mapper.UserMapper;
import com.qcby.mybatisplus1122.service.UserService;
import org.springframework.stereotype.Service;
/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
注:
ServiceImpl中:
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T>
- 第一个参数M 必须是BaseMapper的子类(即UserMapper必须继承BaseMapper)。
- 第二个参数T 必须要和BaseMapper的T一致。并且要和上面代码中的IService 的 T 完全相同。因为 ServiceImpl 实现了 IService。
4.3 IService接口里的方法
新建测试类
@SpringBootTest
public class ServiceTest {
@Autowired
private UserService userService;
}
4.3.1 新增
-
插入一条记录(选择字段,策略插入)
/**
- 插入一条记录(选择字段,策略插入)
- @param entity 实体对象
*/
default boolean save(T entity) {
return SqlHelper.retBool(getBaseMapper().insert(entity));
}
@Test
public void Save(){
User user = new User(null, "张三", 23, "zhangsan@qcby.com");
//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
//1992568912290516994
Boolean result = userService.save(user);
System.out.println(result);
} -
批量插入
SQL长度有限制,海量数据插入单条SQL无法实行,因此MP将批量插入放在了通用Service中实现,而不是通用Mapper。
普通批量插入
/**
* 插入(批量)
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
注:@Transactional(rollbackFor = Exception.class)的解释见4 Spring配置事务。
DEFAULT_BATCH_SIZE表示按默认批次插入。默认是1000.
@Test
public void SaveBatch(){
User user1 = new User(null, "张三", 23, "zhangsan@qcby.com");
User user2 = new User(null, "张三", 23, "zhangsan@qcby.com");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
Boolean result = userService.saveBatch(list);
System.out.println(result);
}
按指定批次批量插入
/**
* 插入(批量)
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
*/
boolean saveBatch(Collection<T> entityList, int batchSize);
-
Collection entityList:
- Collection: 这是 Java 中的一个集合接口,List、Set 等都实现了这个接口。所以你可以传入一个 List、Set 等。
- T: 这是一个泛型参数,代表你要操作的实体类类型,比如 User、Product 等。
-
int batchSize:
-
int: 整数类型。
-
作用: 这个参数指定了每一批次插入的数据量。
-
boolean: 返回一个布尔值。
- true: 表示所有批次的插入操作都成功了。
-
false: 表示至少有一个批次的插入操作失败了。
注: -
需要batchSize的原因是因为,如果你的 entityList 里有 1000 个对象,并且你把 batchSize 设置为 1000,那么 MyBatis-Plus 会尝试构造一个非常长的 SQL 语句。如果太长会超过数据库接收的最大数据包大小,导致操作失败。此外数据库解析和执行如此长的一条 SQL 语句本身就是一个性能负担。
-
如果我分批插入如果同样是 1000 个对象,但你把 batchSize 设置为 100,那么 MyBatis-Plus 会自动将这 1000 个对象分成 10 个批次,循环执行 10 次插入操作,每次只插入 100 条数据(写在同一个insert语句里)。这样可以避免SQL语句过长,并且性能更好。
@Test
public void SaveBatch1(){
User user1 = new User(null, "张三", 23, "zhangsan@qcby.com");
User user2 = new User(null, "张三", 23, "zhangsan@qcby.com");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) 执行两次
Boolean result = userService.saveBatch(list,1);
System.out.println(result);
}
- 批量修改插入
普通批量修改插入
/**
* 批量修改插入
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
这个方法是 MyBatis-Plus 提供的批量 "保存或更新"工具,核心逻辑是:
-
遍历传入的 entityList 集合,对每个实体:
- 若实体的主键已存在(数据库中能查到对应主键的记录),则执行更新操作(UPDATE);
-
若实体的主键不存在(数据库中无对应主键的记录),则执行插入操作(INSERT);
简单说:能更则更,不能更则插,无需你手动判断是新增还是修改。@Test
public void saveOrUpdateBatch(){
User user1 = new User(1992568912290516994l, "王五", 23, "zhangsan@qcby.com");
User user2 = new User(5l, "张三", 23, "zhangsan@qcby.com");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
//先select在决定要干什么
Boolean res = userService.saveOrUpdateBatch(list);
System.out.println(res);
}

按指定批次批量修改插入
/**
* 批量修改插入
*
* @param entityList 实体对象集合
* @param batchSize 每次的数量
*/
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
@Test
public void saveOrUpdateBatch1(){
User user1 = new User(1992568912290516994l, "王五1", 56, "zhangsan@qcby.com");
User user2 = new User(9l, "张三", 23, "zhangsan@qcby.com");
User user3 = new User(7l, "张三", 23, "zhangsan@qcby.com");
User user4 = new User(8l, "张三", 23, "zhangsan@qcby.com");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//先select在决定要干什么
Boolean res = userService.saveOrUpdateBatch(list,2);
System.out.println(res);
}
