ThreadPoolExecutor实现批量插入
一:在run()方法里写插入
1 package com.smartdata.pms.thread;
2
3 import com.smartdata.pms.entity.PmsProduct;
4 import com.smartdata.pms.mapper.PmsProductMapper;
5 import lombok.extern.slf4j.Slf4j;
6
7 import java.util.List;
8
9 /**
10 * @ProjectName: smartdata
11 * @Package: com.smartdata.pms.thread
12 * @ClassName: InsertBatchRun
13 * @Author: heluwei
14 * @Description:
15 * @Date: 2020/3/22 16:36
16 * @Version: 1.0
17 */
18 @Slf4j
19 public class InsertBatchRun implements Runnable {
20 //数据层访问
21 private PmsProductMapper pmsProductMapper;
22 //具体插入批次
23 private int batch;
24
25 //插入的数据
26 private List<PmsProduct> list;
27
28 public InsertBatchRun(PmsProductMapper pmsProductMapper,List<PmsProduct> list,int batch) {
29 this.pmsProductMapper = pmsProductMapper;
30 this.list = list;
31 this.batch = batch;
32 }
33 @Override
34 public void run() {
35 try {
36 for(int i=0;i<list.size();i++){
37 this.pmsProductMapper.insert(list.get(i));
38 }
39 log.info("第" + this.batch + "批次插入成功");
40 } catch (Exception e) {
41 log.error("第" + this.batch + "批次插入失败");
42 }
43
44 }
45 }
注意:在使用***Mapper的时候。不能使用@Autowired,因为多线程环境下,防止注入。
二:使用线程池
1 package com.smartdata.pms.utils;
2
3 import com.smartdata.pms.entity.PmsProduct;
4 import com.smartdata.pms.mapper.PmsProductMapper;
5 import com.smartdata.pms.thread.InsertBatchRun;
6 import lombok.extern.slf4j.Slf4j;
7
8 import java.util.List;
9 import java.util.concurrent.ArrayBlockingQueue;
10 import java.util.concurrent.ThreadPoolExecutor;
11 import java.util.concurrent.TimeUnit;
12
13 /**
14 * @ProjectName: smartdata
15 * @Package: com.smartdata.pms.utils
16 * @ClassName: ExecutorUtils
17 * @Author: heluwei
18 * @Description:
19 * @Date: 2020/3/22 16:39
20 * @Version: 1.0
21 */
22 @Slf4j
23 public class ExecutorUtils {
24 private static final int CORE_POOL_SIZE = 5; //核心线程数为 5
25 private static final int MAX_POOL_SIZE = 10; //最大线程数 10
26 private static final int QUEUE_CAPACITY = 100; //
27 private static final Long KEEP_ALIVE_TIME = 1L; //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
28
29 public static void executeThreadPool(PmsProductMapper pmsProductMapper, List<PmsProduct> pmsProductList){
30 //使用阿里巴巴推荐的创建线程池的方式
31 //通过ThreadPoolExecutor构造函数自定义参数创建
32 ThreadPoolExecutor executor = new ThreadPoolExecutor(
33 CORE_POOL_SIZE,
34 MAX_POOL_SIZE,
35 KEEP_ALIVE_TIME, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
36 TimeUnit.SECONDS, //时间单位
37 new ArrayBlockingQueue<>(QUEUE_CAPACITY), //任务队列,用来储存等待执行任务的队列
38 new ThreadPoolExecutor.CallerRunsPolicy()); //饱和策略,简单点说就是后面排队的线程就在那儿等着。
39 //被拒绝的任务在主线程中运行,所以主线程就被阻塞了,别的任务只能在被拒绝的任务执行完之后才会继续被提交到线程池执行
40 long start = System.currentTimeMillis();
41 //计数器
42 int size = 0;
43 for (int i = 0; i < (Math.round((pmsProductList.size() / 2000)+0.5)); i++) {
44 int startLen = i * 2000;
45 int endLen = ((i + 1) * 2000 > pmsProductList.size() ? pmsProductList.size() - 1 : (i + 1) * 2000);
46 List<PmsProduct> threadList = pmsProductList.subList(startLen, endLen);
47 size = size + threadList.size();
48 executor.execute(new InsertBatchRun(pmsProductMapper, threadList, i));
49 }
50 System.err.println("插入数据总条数:" + size);
51 long end = System.currentTimeMillis();
52 log.error("查询耗时:" + (end - start));
53
54 //终止线程池
55 // void shutdown() 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。若已经关闭,则调用没有其他作用。
56 executor.shutdown();
57 //boolean isTerminated()
58 //若关闭后所有任务都已完成,则返回true。注意除非首先调用shutdown或shutdownNow,否则isTerminated永不为true。
59 while (!executor.isTerminated()) {
60 //System.out.println("线程池还没有完全关闭!!!");
61 }
62 log.info("插入完成:"+(end - start));
63 }
64 }
三:要导入的信息
1 @SysLog("导入商品")
2 @PostMapping("importProduct")
3 public R importProduct(@RequestParam(value = "file", required = false) MultipartFile excelFile) {
4 //============================使用模板======================================================
5 InputStream inputStream = null;
6 try {
7 // 使用模板导入——接收上传文件
8 inputStream = excelFile.getInputStream();
9 // 读取表格数据
10 List<PmsProduct> pmsProductList = EasyExcel.read(inputStream, PmsProduct.class, null).headRowNumber(1).sheet(0).doReadSync();
11 // TODO 根据业务处理objectList……
12 ExecutorUtils.executeThreadPool(pmsProductMapper,pmsProductList);
13 /*pmsProductList.forEach(pmsProduct -> {
14 pmsProductService.save(pmsProduct);
15 });*/
16 } catch (IOException e) {
17 e.printStackTrace();
18 } finally {
19 if (inputStream != null) {
20 try {
21 inputStream.close();
22 } catch (IOException e) {
23 e.printStackTrace();
24 }
25 }
26 }
27 return new R();
28 }
四:对应的实体类
1 package com.smartdata.pms.entity;
2
3 import com.alibaba.excel.annotation.ExcelIgnore;
4 import com.alibaba.excel.annotation.ExcelProperty;
5 import com.alibaba.excel.annotation.write.style.ColumnWidth;
6 import com.baomidou.mybatisplus.annotation.IdType;
7 import com.baomidou.mybatisplus.annotation.TableId;
8 import com.baomidou.mybatisplus.annotation.TableLogic;
9 import com.baomidou.mybatisplus.annotation.TableName;
10 import com.baomidou.mybatisplus.extension.activerecord.Model;
11 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
12 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
13 import lombok.Data;
14 import lombok.EqualsAndHashCode;
15
16 import java.time.LocalDateTime;
17
18 /**
19 * @ProjectName: smartdata
20 * @Package: com.smartdata.pms.entity
21 * @ClassName: PmsProduct
22 * @Author: heluwei
23 * @Description: 商品列表
24 * @Date: 2019/12/29 15:03
25 * @Version: 1.0
26 */
27 @Data
28 @EqualsAndHashCode(callSuper = true)
29 @TableName("pms_product")
30 public class PmsProduct extends Model<PmsProduct> {
31 private static final long serialVersionUID = 1L;
32 @TableId(value = "pro_id", type = IdType.AUTO)
33 @JsonSerialize(using = ToStringSerializer.class)//解决long精度丢失问题
34 @ExcelProperty(value = "序号",index = 0)
35 @ColumnWidth(35)
36 private Long proId; //商品ID
37
38 @ExcelProperty(value = "商品编号",index = 1)
39 @ColumnWidth(35)
40 private String proNo; //商品名称
41
42 @ExcelProperty(value = "商品名称",index = 2)
43 @ColumnWidth(35)
44 private String proName; //商品编号
45
46 @ExcelProperty(value = "商品价格",index = 3)
47 @ColumnWidth(35)
48 private Float proPrice; //商品价格
49
50 @ExcelProperty(value = "商品类别",index = 4)
51 @ColumnWidth(35)
52 private Long proCategoryId; //商品类别
53
54 @ExcelProperty(value = "商品描述",index = 5)
55 @ColumnWidth(35)
56 private String proDescription; //商品描述
57
58 @ExcelProperty(value = "商品图片路径",index = 6)
59 @ColumnWidth(35)
60 private String proImage; //商品图片路径
61
62 @ExcelProperty(value = "商品库存",index = 7)
63 @ColumnWidth(35)
64 private Long proInventory ; //商品库存
65
66 @ExcelProperty(value = "商品销量",index = 8)
67 @ColumnWidth(35)
68 private Long proSail; //商品销量
69
70 @ExcelProperty(value = "商品规格",index = 9)
71 @ColumnWidth(35)
72 private String proSize; //商品规格
73
74 @ExcelProperty(value = "是否热销",index = 10)
75 @ColumnWidth(35)
76 private String IsHot; //是否热销 0是 ,-1不是
77
78 @ExcelProperty(value = "是否推荐",index = 11)
79 @ColumnWidth(35)
80 private String IsReconnend; //是否推荐 0是,-1不是
81
82 @ExcelIgnore
83 private LocalDateTime proCreateTime; //上架时间
84 @ExcelIgnore
85 private LocalDateTime proUpdateTime;
86 /**
87 * 是否删除 -1:已删除 0:正常
88 */
89 @TableLogic
90 @ExcelIgnore
91 private String delFlag;
92 }
Excel表:
在使用Math.ceil()函数的时候。5.013给我计算成了5.我想保存的是6.
解决方案:用四舍五入函数+0.5
double ceil = Math.round(5.013+0.5);输出6.
五:前台
1 //指定允许上传的文件类型
2 upload.render({
3 elem: '#importFile'
4 ,url: '/pms/pmsPro/importProduct'
5 , method: 'POST'
6 ,accept: 'file' //普通文件
7 ,exts: 'xlsx' //只允许上传压缩文件
8 , headers: {
9 Authorization: 'Bearer ' + access_token,
10 }
11 ,done: function(res){
12 layer.msg(res.msg);
13 layui.table.reload('lay-Product-list'); //重载表格
14 }
15 });