摘要
现在写crud越来越得心应手了,主要是在一个领域内重复,写久了,会发现万变不离其宗,但是偶尔也会遇到一点问题,虽然很快就能解决,还是觉得有必要分享一下。
正文
需求就是因为数据量过大,就实现一个类似于异步分批计算,最后再取回合并的功能。
但是直接使用subList,发现原数组的值被改了,简单的分析了一下代码。
1
2
| tempList = list.subList(0, batchNumber);
tempList.clear();
|
是因为我对截取的List进行了清空处理,导致原List改变了,由此处也可知subList其实是指向了原List截取的部分,如果对他清除了,原List也就会改变了。
发现了这个原因,实现一个分批的功能就简单多了。
分批计算的是项目中的,比较复杂。
我下面以分批保存数据库为例,复现一下这个问题,这是一个完整的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| /**
* 同步保存
*
* @param list
*/
private void batchSaveSync(List<Student> list) {
int slice = slice(list.size(), batchNumber);
for (int i = 0; i < slice; i++) {
List<Student> tempList;
if (batchNumber > list.size()) {
//前闭后开
tempList = list.subList(0, list.size());
} else {
tempList = list.subList(0, batchNumber);
}
crudRepository.saveAll(tempList);
//因为SubList是指向的地址,如果将该区域清掉,原List也会受到影响,所以就可以继续使用subList从0开始
tempList.clear();
}
}
/**
* 异步通过线程池保存
*
* @param list
*/
private void batchSaveAsync(List<Student> list) {
ExecutorService executorService = new ExecutorConfig().executorService();
int slice = slice(list.size(), batchNumber);
for (int i = 0; i < slice; i++) {
List<Student> tempList;
if (batchNumber > list.size()) {
//前闭后开
tempList = list.subList(0, list.size());
} else {
tempList = list.subList(0, batchNumber);
}
BatchSaveCallable callable = new BatchSaveCallable(tempList);
executorService.submit(callable);
//因为SubList是指向的地址,如果将该区域清掉,原List也会受到影响,所以就可以继续使用subList从0开始
tempList.clear();
}
}
/**
* 分组
* [java分页算法 - SegmentFault 思否](https://segmentfault.com/a/1190000018350964)
*
* @param size
* @param batchNumber
* @return
*/
private Integer slice(int size, int batchNumber) {
return (size - 1) / batchNumber + 1;
}
|
源码meethigher/batch-save: batch-save