首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >02-MybatisPlus批量插入性能够吗?

02-MybatisPlus批量插入性能够吗?

作者头像
JavaEdge
发布2025-06-01 09:12:10
发布2025-06-01 09:12:10
3180
举报
文章被收录于专栏:JavaEdgeJavaEdge

1 前言

“不要用 mybatis-plus 的批量插入,它其实也是遍历插入,性能很差的”。真的吗?他们的立场如下:

  1. 遍历插入,反复创建。这是一个重量级操作,所以性能差。这里不用看源码也知道,因为这个和mybatis-plus没关系,而且我们现在使用SpringBoot,一般也用它的JDBC启动依赖。连接和连接池不是本文重点,总之这观点纯属无稽之谈,和不懂技术的领导说话一个德行
  2. 一条 insert 就一次网络IO,数量多了,这是个很可观且没必要的开销,所以性能差

2 show me源码!

对第2个观点,结合源码来看吧!

2.1 环境
① mybatis-plus 3.5.3.1

pom.xml:

② application.yml
代码语言:javascript
复制
Spring:
  # 使用默认的连接池库 
  datasource:
    url: "*****"
    username: "****"
    password: "****"

Service使用之处:

2.2 进入saveBatch
代码语言:javascript
复制
com.baomidou.mybatisplus.extension.service.IService#saveBatch(java.util.Collection)

会给我们这个批量操作开启事务(若是期望插入一条就成功一条,该批量方法就不适用);

且有限制提交数量,默认1000。

来到ServiceImpl实现类:

可见,MP批量插入是一条条插入的,但是这个一次次的遍历是真的发送给MySQL了吗?。只要记得这里有一个钩子,后面会回调回来执行。

代码语言:javascript
复制
/**
 * 获取mapperStatementId
 *
 * @param sqlMethod 方法名
 * @return 命名id
 * @since 3.4.0
 */
protected String getSqlStatement(SqlMethod sqlMethod) {
    return SqlHelper.getSqlStatement(mapperClass, sqlMethod);
}

/**
 * 执行批量操作
 *
 * @param list      数据集合
 * @param batchSize 批量大小
 * @param consumer  执行方法
 * @param <E>       泛型
 * @return 操作结果
 * @since 3.3.1
 */
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
    return SqlHelper.executeBatch(this.entityClass, this.log, list, batchSize, consumer);
}
3 SqlHelper#executeBatch(Class<?>, Log, Collection, int, BiConsumer<SqlSession,E>)
代码语言:javascript
复制
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.Collection, int, java.util.function.BiConsumer<org.apache.ibatis.session.SqlSession,E>)
代码语言:javascript
复制
/**
 * 执行批量操作
 *
 * @param entityClass 实体类
 * @param log         日志对象
 * @param list        数据集合
 * @param batchSize   批次大小
 * @param consumer    consumer
 * @param <E>         T
 * @return 操作结果
 * @since 3.4.0
 */
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
    Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
    return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> {
        int size = list.size();
        int idxLimit = Math.min(batchSize, size);
        int i = 1;
        for (E element : list) {
            consumer.accept(sqlSession, element);
            if (i == idxLimit) {
                sqlSession.flushStatements();
                idxLimit = Math.min(idxLimit + batchSize, size);
            }
            i++;
        }
    });
}

sqlSession从哪来的?看executeBatch。

4 SqlHelper#executeBatch(Class<?> entityClass, Log log, Consumer consumer)
代码语言:javascript
复制
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.function.Consumer<org.apache.ibatis.session.SqlSession>)
代码语言:javascript
复制
public static boolean executeBatch(Class<?> entityClass, Log log, Consumer<SqlSession> consumer) {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    try {
        consumer.accept(sqlSession);
        //非事务情况下,强制commit。
        sqlSession.commit(!transaction);
    }
}

结合前面代码,这里是到了1000(默认1000,并且我批量保存的list超过1000),就会开启会话,将内存的SQL全部刷到MySQL,然后回去继续遍历。

总结

MP批量插入虽然是遍历插入,但不是一个insert就一次IO,而是打包了一次发送一批,所以性能没太大问题。但不是鼓励大家都用这批量插入,实际工作有更多要求,有时简单的批量插入没法满足。还是看实际情况决定。

扩展

如果使用mybatis-plus 3.4+ 版本,并且连接的是 MySQL 8.0 或更高版本的数据库,那么 mybatis-plus将会自动利用MySQL 8.0 的原生批量插入功能来执行批量插入操作。

具体实现的关键是在mybatis-plus的底层使用了mybatis-plus的批量新增方法时,mybatis-plus会将待插入的对象列表传递给底层的。

注意确保以下条件满足才能利用:

使用 MySQL 8.0 或更高版本的数据库

使用兼容 MySQL 8.0 的 JDBC 驱动程序(如 mysql-connector-java 版本 8.0 或更高)

使用 mybatis-plus 3.4+ 版本

参考:https://www.jianshu.com/p/a387879ccb97

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 前言
  • 2 show me源码!
    • 2.1 环境
      • ① mybatis-plus 3.5.3.1
      • ② application.yml
    • 2.2 进入saveBatch
      • 3 SqlHelper#executeBatch(Class<?>, Log, Collection, int, BiConsumer<SqlSession,E>)
      • 4 SqlHelper#executeBatch(Class<?> entityClass, Log log, Consumer consumer)
  • 总结
  • 扩展
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档