springboot + mybatisPlus + mysql环境,批量保存的几种方法:

1.使用MybatisPlus自带的Iservice接口

BaseMapper中为提供批量插入接口,但是在com.baomidou.mybatisplus.extension.service.IService接口中提供了saveBatch批量插入方法。

1.1入门使用

  1. 新建一个接口,继承Iservice接口,泛型为被操作的实体类
package com.wsh.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.wsh.entity.Order;

public interface BatchInsertService extends IService<Order> {
}

  1. 创建一个方法,继承ServiceImpl,并且实现上述接口BatchInsertService
package com.wsh.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsh.mapper.OrderMapper;
import com.wsh.entity.Order;
import org.springframework.stereotype.Service;

@Service
public class BatchInsertServiceImpl extends ServiceImpl<OrderMapper,Order> implements BatchInsertService{

}

其中,extends ServiceImpl<OrderMapper,Order>Order是被操作的实体类Ordermapper是继承BaseMapper的自定义接口,如下:

package com.wsh.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wsh.entity.Order;

// 使用mybatis-plus增强接口
public interface OrderMapper extends BaseMapper<Order> {

}
  1. 批量保存测试
package com.wsh;

import com.wsh.service.BatchInsertService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import com.wsh.entity.Order;
import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Date;

@SpringBootTest
public class TestBatchInsertService {

    @Resource
    private BatchInsertService batchInsertService;

    @Test
    public void testBatchSave(){

        long start = System.currentTimeMillis();

        ArrayList<Order> orders = new ArrayList<>();

        for (int i = 0; i < 100000; i++) { //十万条数据

            Order order = new Order();
            order.setName("wsh"+i);
            order.setOrderDate(new Date());
            orders.add(order);
        }

        boolean b = batchInsertService.saveBatch(orders, 50);
        long end = System.currentTimeMillis();
        System.out.println("保存时间为:" + (end - start)); //73474
        System.out.println(b);
    }
}

测试结果为(部分展示):

==>  Preparing: INSERT INTO orders ( order_id, order_date, order_name ) VALUES ( ?, ?, ? ) 
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99951(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99952(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99953(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99954(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99955(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99956(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99957(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99958(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99959(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99960(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99961(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99962(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99963(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99964(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99965(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99966(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99967(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99968(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99969(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99970(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99971(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99972(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99973(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99974(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99975(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99976(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99977(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99978(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99979(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99980(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99981(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99982(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99983(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99984(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99985(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99986(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99987(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99988(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99989(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99990(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99991(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99992(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99993(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99994(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99995(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99996(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99997(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99998(String)
==> Parameters: 0(Integer), 2021-07-28 10:16:42.773(Timestamp), wsh99999(String)
保存时间为:73474
true

1.2 原理方法

Iservice接口中saveBatch方法:

  /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     */
    boolean saveBatch(Collection<T> entityList, int batchSize);

ServiceImpl.java实现类中的saveBatch方法:

    /**
    * 批量插入
    *
    * @param entityList ignore
    * @param batchSize ignore
    * @return ignore
    */
   @Transactional(rollbackFor = Exception.class)
   @Override
   public boolean saveBatch(Collection<T> entityList, int batchSize) {
       String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
       try (SqlSession batchSqlSession = sqlSessionBatch()) {
           int i = 0;
           for (T anEntityList : entityList) {
               batchSqlSession.insert(sqlStatement, anEntityList);
               if (i >= 1 && i % batchSize == 0) {
                   batchSqlSession.flushStatements();
               }
               i++;
           }
           batchSqlSession.flushStatements();
       }
       return true;
   }
 

sqlSessionBatch

    /**
     * 批量操作 SqlSession
     */
    protected SqlSession sqlSessionBatch() {
        return SqlHelper.sqlSessionBatch(currentModelClass());
    }



    /**
     * 批量操作 SqlSession
     *
     * @param clazz 实体类
     * @return SqlSession
     */
    public static SqlSession sqlSessionBatch(Class<?> clazz) {
        // TODO 暂时让能用先,但日志会显示Closing non transactional SqlSession,因为这个并没有绑定.
        return GlobalConfigUtils.currentSessionFactory(clazz).openSession(ExecutorType.BATCH);
    }

注意:openSession(ExecutorType.BATCH),到这里就熟悉了。
插入十万条数据,时间为:73474

2.使用MybatisPlus自定义新增

2.1配置工作

注: 仅适用于MySQL

  1. 创建自定义数据方法注入类
package com.wsh.util;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.additional.InsertBatchSomeColumn;

import java.util.List;


public class EasySqlInjector extends DefaultSqlInjector {

 @Override
 public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
     // 防止父类方法不可用
     List<AbstractMethod> methodList = super.getMethodList(mapperClass);
     methodList.add(new InsertBatchSomeColumn());
     return methodList;
 }
}
  1. 在MybatisPlus配置文件MybatisPlusConfig加入自定义
package com.wsh.config;

import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.wsh.util.EasySqlInjector;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@EnableTransactionManagement
@Configuration
@MapperScan("com.wsh.mapper")
public class MybatisPlusConfig {

    @Bean
    public EasySqlInjector easySqlInjector(){
        return new EasySqlInjector();
    }
}
  1. 扩展通用Mapper,支持数据批量插入,即:创建EasyBaseMapper接口继承BaseMapper
package com.wsh.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.Collection;

/**
 * @author suahng
 * @date 2021-07-21 20:47
 * @dec
 */
public interface EasyBaseMapper<T> extends BaseMapper<T> {


    /**
     * 批量插入,仅使用批量插入
     * @param entityList 实体列表
     * @return 影响行数
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);
}
  1. 定义业务mapper接口,继承刚刚扩展的EasyBaseMapper
package com.wsh.mapper;
import com.wsh.entity.Order;
import org.springframework.stereotype.Repository;

@Repository
public interface EasyMapper extends EasyBaseMapper<Order> {
}
  1. 定义Service接口
package com.wsh.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.wsh.entity.Order;

import java.util.Collection;


public interface EasyService extends IService<Order> {

    /**
     * 批量插入,仅适用于 mysql
     * @param orderList
     * @return
     */
    public Integer BatchSave(Collection<Order> orderList);
}
  1. 定义service接口的实现类
package com.wsh.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsh.mapper.EasyBaseMapper;
import com.wsh.mapper.EasyMapper;
import com.wsh.entity.Order;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;


@Service
public class EasyServiceImpl extends ServiceImpl<EasyMapper, Order> implements EasyService{



    @Override
    public Integer BatchSave(Collection<Order> orderList) {
        return baseMapper.insertBatchSomeColumn(orderList);
    }
}

2.2 批量插入测试

package com.wsh;

import com.wsh.entity.Order;
import com.wsh.service.EasyServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;

@SpringBootTest
public class TestEasyService {

    @Resource
    EasyServiceImpl easyService;

    @Test
    public void testBatchSave(){

        long start = System.currentTimeMillis();

        ArrayList<Order> orders = new ArrayList<>();

        for (int i = 0; i < 100000; i++) {

            Order order = new Order();
            order.setName("hcy"+i);
            order.setOrderDate(new Date());
            orders.add(order);
        }

        Integer b = easyService.BatchSave(orders);
        long end = System.currentTimeMillis();
        System.out.println("保存时间为:" + (end - start));//6348 6093 4320
        System.out.println(b);
    }
}

结果:
在这里插入图片描述

0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16065(String), 0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16066(String), 0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16067(String), 0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16068(String), 0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16069(String), 0(Integer), 2021-07-28 11:28:02.54(Timestamp), hcy16070(String), 0(Inte<...>.556(Timestamp), hcy99998(String), 0(Integer), 2021-07-28 11:28:02.556(Timestamp), hcy99999(String)
<==    Updates: 100000
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d50a7ca]
保存时间为:4223
100000

插入十万条数据,时间为:4223,比上一个方法减少了大约一半的时间。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐