MybatisPlus——service批量新增

打印 上一主题 下一主题

主题 677|帖子 677|积分 2031

Service接口

 批量新增

批量插入10万条用户数据,并作出对比:


  • 普通for循环插入
  • IService的批量插入
  1. @Test
  2. void testSaveOneByOne() {
  3.     long b = System.currentTimeMillis();
  4.     for (int i = 1; i <= 100000; i++) {
  5.         userService.save(buildUser(i));
  6.     }
  7.     long e = System.currentTimeMillis();
  8.     System.out.println("耗时:" + (e - b));
  9. }
  10. private User buildUser(int i) {
  11.     User user = new User();
  12.     user.setUsername("user_" + i);
  13.     user.setPassword("123");
  14.     user.setPhone("" + (18688190000L + i));
  15.     user.setBalance(2000);
  16.     user.setInfo("{"age": 24, "intro": "英文老师", "gender": "female"}");
  17.     user.setCreateTime(LocalDateTime.now());
  18.     user.setUpdateTime(user.getCreateTime());
  19.     return user;
  20. }
复制代码

  1. @Test
  2. void testSaveBatch() {
  3.     // 准备10万条数据
  4.     List<User> list = new ArrayList<>(1000);
  5.     long b = System.currentTimeMillis();
  6.     for (int i = 1; i <= 100000; i++) {
  7.         list.add(buildUser(i));
  8.         // 每1000条批量插入一次
  9.         if (i % 1000 == 0) {
  10.             userService.saveBatch(list);
  11.             list.clear();
  12.         }
  13.     }
  14.     long e = System.currentTimeMillis();
  15.     System.out.println("耗时:" + (e - b));
  16. }
复制代码
实验结果如下:

可以看到利用了批处理以后,比逐条新增效率提高了10倍左右。
检察一下MybatisPlus源码:
  1. @Transactional(rollbackFor = Exception.class)
  2. @Override
  3. public boolean saveBatch(Collection<T> entityList, int batchSize) {
  4.     String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
  5.     return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
  6. }
  7. // ...SqlHelper
  8. public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
  9.     Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
  10.     return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> {
  11.         int size = list.size();
  12.         int idxLimit = Math.min(batchSize, size);
  13.         int i = 1;
  14.         for (E element : list) {
  15.             consumer.accept(sqlSession, element);
  16.             if (i == idxLimit) {
  17.                 sqlSession.flushStatements();
  18.                 idxLimit = Math.min(idxLimit + batchSize, size);
  19.             }
  20.             i++;
  21.         }
  22.     });
  23. }
复制代码
        可以发现其实MybatisPlus的批处理是基于PrepareStatement的预编译模式,然后批量提交,终极在数据库实验时照旧会有多条insert语句,逐条插入数据。SQL类似这样:
  1. Preparing: INSERT INTO user ( username, password, phone, info, balance, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )
  2. Parameters: user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01
  3. Parameters: user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01
  4. Parameters: user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01
复制代码
而如果想要得到最佳性能,最好是将多条SQL合并为一条,像这样:
  1. INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )
  2. VALUES
  3. (user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),
  4. (user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),
  5. (user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),
  6. (user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);
复制代码
        在MySQL的客户端连接参数中有这样的一个参数:rewriteBatchedStatements。顾名思义,就是重写批处理的statement语句。这个参数的默认值是false,我们必要修改连接参数,将其配置为true
        修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true:
  1. spring:
  2.   datasource:
  3.     url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
  4.     driver-class-name: com.mysql.cj.jdbc.Driver
  5.     username: root
  6.     password: MySQL123
复制代码
再次测试插入10万条数据,可以发现速度有非常明显的提拔:

在ClientPreparedStatement的executeBatchInternal中,有判断rewriteBatchedStatements值是否为true并重写SQL的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

盛世宏图

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表