工具类中的用多线程做插入数据的方法
/**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;
}