
目录4 IService4.1 概述4.2 创建接口和实现类4.3 IService接口里的方法4.3.1 新增普通批量插入按指定批次批量插入普通批量修改插入按指定批次批量修改插入4 IService4.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 IServiceUser { }注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 ServiceImplUserMapper,User implements UserService { }注ServiceImpl中public class ServiceImplM extends BaseMapperT, T implements IServiceT第一个参数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, zhangsanqcby.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(CollectionT 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, zhangsanqcby.com); User user2 new User(null, 张三, 23, zhangsanqcby.com); ListUser 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(CollectionT entityList, int batchSize);Collection entityListCollection: 这是 Java 中的一个集合接口List、Set 等都实现了这个接口。所以你可以传入一个 List、Set 等。T: 这是一个泛型参数代表你要操作的实体类类型比如 User、Product 等。int batchSizeint: 整数类型。作用: 这个参数指定了每一批次插入的数据量。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, zhangsanqcby.com); User user2 new User(null, 张三, 23, zhangsanqcby.com); ListUser 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(CollectionT entityList) { return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE); }这个方法是 MyBatis-Plus 提供的批量 “保存或更新”工具核心逻辑是遍历传入的 entityList 集合对每个实体若实体的主键已存在数据库中能查到对应主键的记录则执行更新操作UPDATE若实体的主键不存在数据库中无对应主键的记录则执行插入操作INSERT简单说能更则更不能更则插无需你手动判断是新增还是修改。Test public void saveOrUpdateBatch(){ User user1 new User(1992568912290516994l, 王五, 23, zhangsanqcby.com); User user2 new User(5l, 张三, 23, zhangsanqcby.com); ListUser 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(CollectionT entityList, int batchSize);Test public void saveOrUpdateBatch1(){ User user1 new User(1992568912290516994l, 王五1, 56, zhangsanqcby.com); User user2 new User(9l, 张三, 23, zhangsanqcby.com); User user3 new User(7l, 张三, 23, zhangsanqcby.com); User user4 new User(8l, 张三, 23, zhangsanqcby.com); ListUser 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); }