多线程使用:batchInsert

工具类中的用多线程做插入数据的方法

   /**400一组(按组开多线程),200一插
     * 使用map对象的key作为参数列表拼接sql
     * 动态构建添加参数列表以及拼接组装sql
     * @param parms 执行sql语句中需要的参数集合,string存储表名,value存储map对象集合
     * @return
     */
    public void batchInsert(Map<String, List<Map<String, Object>>> parms, Long startTime) throws Exception {
        try {
            //创建一个线程池,无界队列
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    4,
                    4,
                    0L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<Runnable>(),
                    Executors.defaultThreadFactory());
            // 预先启动所有核心线程
            executor.prestartAllCoreThreads();
            //400一组
            int batchSize = 400;
            // 遍历parms中的所有键值对
            for (Map.Entry<String, List<Map<String, Object>>> entry1 : parms.entrySet()) {
                // 当执行时间超过 90 秒,抛出异常,service层删表
                if (null !=startTime && System.currentTimeMillis() - startTime > 90000) {
                    isRunning = true;
                }
                if (isRunning) {
                    break;
                }
                //驼峰
                List<String> columns = new ArrayList<>();
                //字段
                List<String> columns1 = new ArrayList<>();
                //占位符?
                List<String> values = new ArrayList<>();
                //表名
                String tableName = entry1.getKey();
                //List<Map<String, Object>>
                List<Map<String, Object>> value1 = entry1.getValue();
                // value是List<Map<String, Object>>类型,进行第二次遍历
                List<Map<String, Object>> list =  value1;
                log.info("解析结构化数据,应插入" + tableName + "临时表-" + list.size() + "条!");
                //初始化所需线程数
                int threadCount = (list.size() + batchSize - 1) / batchSize;
                CountDownLatch latch = new CountDownLatch(threadCount);//初始化CountDownLatch
                //结构化数据分为400一组
                List<List<Map<String, Object>>> batchedList = getbatchedList(list, batchSize);
                //获取字段集合和占位符?,拼接sql
                String sql = getSql(columns, columns1, values, tableName, list);
                //批量插入,400一组(多线程),200一插
                for (List<Map<String, Object>> subList : batchedList) {
                    executor.execute(new InsertTask(dataSource, columns, subList, sql, latch, executor));
                }
                latch.await();
            }
            //关闭线程池
            executor.shutdown();
            //检测任务和线程池是否真正关闭
            while (!executor.isTerminated()){
                if (null !=startTime && System.currentTimeMillis() - startTime > 90000) {
                   break;
                }
                Thread.sleep(100);
            }
            if (isRunning) {
                throw new Exception("解析结构化数据,批量插入临时表时异常!");
            }
            log.info("该临时表插入完成----->\n");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("解析结构化数据,批量插入临时表时异常!");
            throw new Exception("batch insert failed",e);
        } finally {
            isRunning = false;
        }
    }




    //获取字段集合和占位符?,拼接sql
    private String getSql(List<String> columns, List<String> columns1, List<String> values, String tableName, List<Map<String, Object>> list) {
        for (Map.Entry<String, Object> entry2 : list.get(0).entrySet()) {
            if (null != entry2.getValue()) {
                //格式转换:驼峰转换为数据库字段(map中存放的格式为驼峰)
                String field = entry2.getKey();
                columns.add(field);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < field.length(); i++) {
                    char c = field.charAt(i);
                    if (Character.isUpperCase(c)) {
                        sb.append("_");
                    }
                    sb.append(Character.toLowerCase(c));
                }
                field = sb.toString().toUpperCase();
                columns1.add(field);
                values.add("?");
            }
        }
        return "INSERT INTO " + tableName + "(" + String.join(",", columns1) + ") VALUES(" + String.join(",", values) + ")";
    }




 /*
     * IntStream.range(n,m)左闭右开
     * mapToObj(n,m)左闭右开
     * list.subList(n,m)左闭右开 截取指定范围的数据
     * @param list
     * @return java.util.List<java.util.List<java.util.Map<java.lang.String,java.lang.Object>>>
     */
    private List<List<Map<String, Object>>> getbatchedList(List<Map<String, Object>> list, int batchSize) {
        List<List<Map<String, Object>>> batchedList =
                //控制组数,每个整数表示一组 左闭右开
                IntStream.range(0, (list.size() + batchSize - 1) / batchSize)
                        //截取指定范围数据映射到对应的组里,i是第几组,从0开始. Math.min()考虑不足600的情况
                        .mapToObj(i -> list.subList(i * batchSize, Math.min((i + 1) * batchSize, list.size())))
                        .collect(Collectors.toList());
        return batchedList;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MyBatis提供了批量插入数据的功能,可以通过多线程来执行批量插入操作。 首先,可以使用Java的ExecutorService来创建一个线程池,通过配置线程池的大小,控制并发执行的线程数量。然后,将需要进行批量插入的数据分成若干个小部分,每个小部分的数据量适当,确保在插入过程中不会产生内存溢出等问题。 接下来,可以将每个小部分的数据分配给线程池中的某个线程进行处理。每个线程都会创建一个自己的SqlSession来执行插入操作。在使用MyBatis的批量插入功能时,需要确保每个线程使用独立的SqlSession,避免线程之间的资源竞争。 在每个线程中,可以使用Mapper接口对应的方法来执行批量插入操作,将对应的数据集合作为参数传入。MyBatis会将这个集合拆分成多条SQL语句进行批量执行,减少与数据库的交互次数,提高性能。 最后,在每个线程处理完对应的数据后,需要记得关闭对应的SqlSession,释放资源。可以使用Java的ExecutorService的shutdown方法来关闭线程池,确保所有的线程都执行完毕。 综上所述,通过多线程的方式来执行MyBatis的批量插入操作,可以充分利用多核CPU的优势,并发处理大量的插入数据,提高插入性能。但需要注意数据的分配、线程的管理等问题,以避免出现线程安全等并发问题。 ### 回答2: MyBatis提供了批量插入数据的功能,可以通过多线程来提高插入速度。 首先,需要创建一个线程池来管理线程。线程池可以使用Java中的ExecutorService来实现,可以使用Executors工具类中的方法创建不同类型的线程池,例如FixedThreadPool或CachedThreadPool。 然后,将需要插入的数据按照一定的规则划分成多个小批量,每个小批量数据交给一个线程来处理。可以使用Java中的线程同步机制来保证每个线程的操作顺序。 在每个线程中,可以使用MyBatis的SqlSession来执行批量插入操作。可以通过配置JDBC的批量处理机制来优化插入性能。在配置文件中设置useGeneratedKeys="true"和keyProperty="id"可以获取自动生成的主键值。 最后,在所有线程的操作完成后,需要手动提交事务并关闭SqlSession。 需要注意的是,在多线程环境下,可能会出现数据安全性的问题,例如多个线程同时插入同一条数据,可能会导致主键冲突。可以通过加锁、使用数据库的唯一约束来解决这个问题。 总之,通过使用多线程和批量插入的方式,可以提高MyBatis插入大量数据的性能和效率。但是在实际应用中,需要根据具体情况来确定合适的线程数量和数据划分规则,以及解决可能出现的并发问题。 ### 回答3: Mybatis的批量插入操作在多线程环境下可以通过以下步骤来实现: 1. 将数据按照批次拆分:将待插入的数据按照指定的批次大小进行拆分,例如每批次100条数据。 2. 创建线程池:使用Java的线程池机制,在多个线程之间共享执行任务。 3. 并发执行插入操作:将拆分的数据均匀地分配给各个线程,在每个线程中执行插入操作。 4. 等待所有线程执行完毕:使用Java的CountDownLatch或者CyclicBarrier等工具类来实现所有线程执行完毕后的等待操作。 5. 提交事务:在所有线程执行完毕后,提交数据库事务,完成批量插入操作。 需要注意的是,在多线程环境下进行批量插入操作需要考虑以下几点: 1. 数据拆分与分配的均衡性:数据拆分后应该尽量保持每个批次的数据量均衡,避免某个线程负载过大或过小。 2. 数据库事务的管理:在多个线程中执行插入操作时,需要保证每个线程执行的插入操作在同一个数据库事务中,避免数据不一致的问题。 3. 异常处理:在每个线程中执行插入操作时,应该做好异常处理,确保插入操作的稳定性和可靠性。 总结起来,使用多线程可以提高Mybatis批量插入操作的执行效率,但需要注意数据的均衡性、数据库事务的管理以及异常处理等问题,确保数据插入的正确性和可靠性。同时,针对具体的需求和环境,可以根据实际情况对多线程的实现方式进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值