当前位置: 首页 > news >正文

MyBatis-Plus 通用 CRUD 操作全景指南

MyBatis-Plus 通用 CRUD 操作全景指南

适用版本:3.5.5+(JDK17+)
目标读者:从“会用”到“精通”,一篇文章掌握全部招式


一、为什么需要“通用 CRUD”

  • 90% 的业务接口 都是单表增删改查 + 分页 + 批量操作
  • 重复 SQL 降低开发效率,增加维护成本
  • MyBatis-Plus 把共性逻辑抽象成 无侵入接口,一行代码完成过去 10 行 XML 的工作量

二、技术栈定位

层级组件职责是否必须
MapperBaseMapper<T>单表原子操作
ServiceIService<T> + ServiceImpl<M,T>组合式、批量化、链式调用
扩展Wrapper<T>动态条件构造

三、核心方法总览(思维导图)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


四、Mapper 层 API(BaseMapper)

4.1 单条操作

// 插入并返回主键
userMapper.insert(user);// 按主键查 / 删 / 改
User u = userMapper.selectById(1L);
int rows = userMapper.deleteById(1L);
rows = userMapper.updateById(user);

4.2 条件操作

// 按列 map
userMapper.selectByMap(Map.of("name", "Tom"));// 条件构造器
LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery().eq(User::getName, "Tom").gt(User::getAge, 18);
List<User> list = userMapper.selectList(wrapper);
Long cnt = userMapper.selectCount(wrapper);

4.3 批量操作

// 批量主键
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
int delRows = userMapper.deleteBatchIds(Arrays.asList(1L, 2L));// 高性能原生批量插入(推荐)
userMapper.insertBatchSomeColumn(entityList);

五、Service 层 API(IService)

5.1 单条 & 批量

// 单条
userService.save(user);
userService.updateById(user);// 批量
userService.saveBatch(list, 1000);          // 每 1000 条提交一次
userService.updateBatchById(list, 500);
userService.saveOrUpdateBatch(list);        // 主键存在则更新

5.2 链式调用(不写 Wrapper)

// 查询链
List<User> tomList = userService.query().like(User::getName, "Tom").list();// 更新链
userService.update().set(User::getAge, 20).eq(User::getId, 1L).update();

5.3 分页 & 存在判断

Page<User> page = userService.page(new Page<>(1, 10),Wrappers.<User>lambdaQuery().gt(User::getAge, 18)
);boolean exists = userService.exists(Wrappers.<User>lambdaQuery().eq(User::getName, "Tom")
);

六、分页实战(只需两步)

  1. 注册插件
@Bean
public MybatisPlusInterceptor interceptor() {MybatisPlusInterceptor mp = new MybatisPlusInterceptor();mp.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return mp;
}
  1. 调用
Page<User> page = userMapper.selectPage(new Page<>(2, 20),Wrappers.<User>lambdaQuery().like(User::getName, "T%")
);

七、批量性能调优

开关说明
rewriteBatchedStatements=trueJDBC 驱动把 N 条 insert 合并成一条 multi-values
batchSize = 1000每 1000 条 flush 一次,减少内存占用
// 1000 条一批,自动分批
userService.saveBatch(list, 1000);

结论先行:
MyBatis-Plus 的批量操作方法 会自动拆分 List 进行分批提交无需人工拆分
你只需要传入完整的 List,框架内部会按你指定的 batchSize(或默认 1000)自动切片并分批执行。


✅ 自动拆分的证据(源码级)
1. saveBatch 源码片段

java

复制

// ServiceImpl.java
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveBatch(Collection<T> entityList, int batchSize) {// 关键:使用 SqlHelper.executeBatch 自动切片return SqlHelper.executeBatch(this.entityClass, this.log, entityList, batchSize,(sqlSession, entity) -> sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), entity));
}
2. executeBatch 内部逻辑

java

复制

// SqlHelper.java
public static <E> boolean executeBatch(Class<?> entityClass, Log log,Collection<E> list, int batchSize,BiConsumer<SqlSession, E> consumer) {int size = list.size();int idxLimit = Math.min(batchSize, size); // 自动计算每批数量for (int i = 0; i < size; i++) {consumer.accept(sqlSession, iterator.next());if (i == idxLimit - 1) { // 达到批次阈值时 flushsqlSession.flushStatements();idxLimit = Math.min(idxLimit + batchSize, size);}}return true;
}

🚫 反例:哪些方法不会自动分批?

表格

复制

方法是否自动分批备注
insertBatchSomeColumn底层使用原生 JDBC 批处理,需手动控制批次
手写 XML ``需自己分批或设置 batchSize

🎯 实战示例
// 自动分批,每 500 条提交一次
userService.saveBatch(userList, 500);// 不指定 batchSize 时,默认 1000
userService.saveBatch(userList);

📌 总结
场景是否自动分批备注
saveBatch / updateBatchById / saveOrUpdateBatch内置自动切片
insertBatchSomeColumn需手动分批
XML 手写批量 SQL需手动分批

结论:日常使用 Plus 的批量方法,放心把完整 List 丢进去即可。

八、自定义通用方法(扩展点)

  1. 继承 AbstractMethod
  2. 注册自定义 SqlInjector
public class LogicDeleteBatchByIds extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(...) {String sql = String.format("UPDATE %s SET deleted = 1 WHERE id IN (%s)",tableInfo.getTableName(),collectionToString(ids));return addUpdateMappedStatement(mapperClass, modelClass, "logicDeleteBatchByIds", sql);}
}

九、常见坑 & 排查

现象排查命令原因
selectOne 抛 TooManyResults日志打印 SQL忘记加 limit
分页 total 为 0Page 对象未注入插件插件未生效
saveOrUpdate 未生效实体主键为空主键策略未配置

十、总结

  • BaseMapper:原子级 API,覆盖 90% 单表需求

  • IService:再封装一次,提供链式、批量化、事务友好

  • Wrapper:让 SQL 像写 Java 一样自然

  • 插件体系:分页、乐观锁、多租户…随插随用

         | `Page` 对象未注入插件 | 插件未生效     |
    

| saveOrUpdate 未生效 | 实体主键为空 | 主键策略未配置 |


十、总结

  • BaseMapper:原子级 API,覆盖 90% 单表需求
  • IService:再封装一次,提供链式、批量化、事务友好
  • Wrapper:让 SQL 像写 Java 一样自然
  • 插件体系:分页、乐观锁、多租户…随插随用

掌握这 20+ 个方法,即可在日常开发中 “不写 XML,不写 SQL” 完成绝大多数数据库交互。

http://www.dtcms.com/a/588831.html

相关文章:

  • 公司网站建设 意义水果营销软文
  • Ernie_health + ProtoNet + Supervised-Contrastive Learning实现小样本意图分类与槽位填充
  • Rust + WebAssembly:让嵌入式设备被浏览器调试
  • 从 LinkedList 血案说起:用 3W 法搭建数据结构知识框架
  • rust操作stm32f1ct86
  • 深入理解大语言模型(6)-Prompt 注入 Prompt 注入
  • Data Mining Tasks|数据挖掘任务
  • rspack为什么能提速?底层逻辑是什么?
  • 深度学习十种食物分类系统1:数据集说明(含下载链接)
  • 应用层协议HTTP(1)
  • mongodb总结
  • seo网站排名厂商定制莱州网站制作
  • web网页开发,在线%聚类,微博,舆情%系统,基于python,pycharm,django,nlp,kmeans,mysql
  • 大型语言模型推理能力评估——李宏毅2025大模型课程第9讲内容
  • WPS国际版18.22 | 集Word,PDF,Sheet,PowerPoint于一体的多功能免费办公套件
  • RHCE DNS实验作业
  • 深圳网站备案wordpress 界面 阴影
  • 【STL源码剖析】从源码看 heap:元素的 “下沉” 与 “上浮”
  • 【LLM】LLaMA-Factory 训练模型入门指南
  • DTrac Rotor
  • 06 Activiti 与 Spring Boot 整合
  • 分布式专题——49 SpringBoot整合ElasticSearch8.x实战
  • 18_FastMCP 2.x 中文文档之FastMCP服务端高级功能:后端存储详解
  • 基于Spring Boot的社团服务系统的设计与实现
  • Spring Boot配置文件加载顺序详解(含Nacos配置中心机制)
  • 基于React+Flask前后端分离的文件搜索系统
  • K8s 集群部署中间件 - yaml 版本(二)
  • zmaiFy音频转录介绍
  • 学校资源网站建设目标关于做电商网站导流项目
  • 【论文阅读与项目复现】Hypothesis Generation with Large Language Models