需求:在开发业务报表时,需要从MySQL数据库读取数据后进行操作,然后写入数据库,使用定时任务跑批。
分析:①兼顾性能,② MySQL没有Oracle那么方便、强大的存储过程。综上所述,使用线程池以分批提交的方案来插入MySQL数据库,对于更新操作、在Java端进行分页等的操作,本方案也支持。代码如下:
1 private void batchDeal(List data, int batchNum) throws InterruptedException {
2 int totalNum = data.size();
3 int pageNum = totalNum % batchNum == 0 ? totalNum / batchNum : totalNum / batchNum + 1;
4 ExecutorService executor = Executors.newFixedThreadPool(pageNum);
5 try {
6 CountDownLatch countDownLatch = new CountDownLatch(pageNum);
7 List subData = null;
8 int fromIndex, toIndex;
9 for (int i = 0; i < pageNum; i++) {
10 fromIndex = i * batchNum;
11 toIndex = Math.min(totalNum, fromIndex + batchNum);
12 subData = data.subList(fromIndex, toIndex);
13 ImportTask task = new ImportTask(subData, countDownLatch);
14 executor.execute(task);
15 }
16 // 主线程必须在启动其它线程后立即调用CountDownLatch.await()方法,
17 // 这样主线程的操作就会在这个方法上阻塞,直到其它线程完成各自的任务。
18 // 计数器的值等于0时,主线程就能通过await()方法恢复执行自己的任务。
19 countDownLatch.await();
20 logger.info("数据操作完成!可以在此开始其它业务");
21 } finally {
22 // 关闭线程池,释放资源
23 executor.shutdown();
24 }
25 }
26
27 class ImportTask implements Runnable {
28 private List list;
29 private CountDownLatch countDownLatch;
30
31 public ImportTask(List data, CountDownLatch countDownLatch) {
32 this.list = data;
33 this.countDownLatch = countDownLatch;
34 }
35
36 @Override
37 public void run() {
38 if (null != list) {
39 // 业务逻辑,例如批量insert或者update
40 logger.info("现在操作的数据是{}", list);
41 }
42 // 发出线程任务完成的信号
43 countDownLatch.countDown();
44 }
45 }
在第1行中,List data表示传入的数据,batchNum表示每一次处理的数量,例如500条等。