批量獲取
開發中,有時候難免需要用到類似findAll()方法,或者說獲取表中所有數據。但是當這個量很大時,一次性從數據庫中加載到內存中,明顯不理智。這時候可以採用批量取的方式,比如batchSize爲500。
/**
* 批量獲取任務,刪除任務
*/
private void cleanTask() {
List<String> projectIds = getAllProjectIds();
if (isNotEmpty(projectIds)) {
int skip = 0;
List<TaskVO> res = null;
do {
res = taskService.findAll(skip, batchSize);
if (res == null || res.isEmpty()) {
break;
}
deleteBatchTask(projectIds, res);
skip = skip + batchSize;
} while (res.size() == batchSize);
}
}
批量刪除
在執行刪除操作時,通常我們會foreach遍歷着刪,但是遍歷一次就是與數據庫的一次交互。更常見地,每一次刪除時,還會有很多相關的級聯刪除操作,這樣更加拉低了頁面的相應。有幾個地方可以優化:比如採用線程池來執行整個的批量刪除操作;比如可以先做假刪除,在夜深人靜時採用定時任務來刪除;再比如,採用批量刪除,也就是in語句。這裏主要說的也是第三種,但是如果採用in進行批量刪除,也需要注意,不能過分信任in的批量,如果數據量過大,一次性in上萬條,數據庫也扛不住,此時就可以對in再進行批量。
// 批量刪除任務
Functional.batchExec(taskIds, delIds -> taskDAO.deleteTaskTrue(delIds), batchSize);
/**
* 批量刪除(真刪除)
*
* @param taskIds 任務ids
*/
public void deleteTaskTrue(List<String> taskIds) {
createDelete().where().in("_id", taskIds).delete();
}
public class Functional {
/**
* 將集合按指定分批大小進行分批操作
*
* @param src
* @param function
* @param batchSize
* @param <K>
*/
public static <K> void batchExec(List<K> src, Consumer<List<K>> function, int batchSize) {
if (src == null || src.isEmpty()) {
return;
}
if (batchSize <= 0) {
batchSize = 1;
}
int loopTimes;
if (src.size() % batchSize == 0) {
loopTimes = src.size() / batchSize;
} else {
loopTimes = src.size() / batchSize + 1;
}
for (int i = 0; i < loopTimes; i++) {
List<K> subList;
if (i == src.size() / batchSize) {
subList = src.subList(i * batchSize, src.size());
} else {
subList = src.subList(i * batchSize, (i + 1) * batchSize);
}
function.accept(subList);
}
}
/**
* 正序排序
*
* @param src
* @param field
*/
public static void ascSort(List src, String field) {
sort(src, field, 1);
}
/**
* 逆序排序
*
* @param src
* @param field
*/
public static void descSort(List src, String field) {
sort(src, field, -1);
}
private static void sort(List src, String field, int direction) {
if (ValidateUtil.isEmpty(src)) {
return;
}
Collections.sort(src, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
Object value1 = BeanUtil.pojo.getProperty(o1, field);
Object value2 = BeanUtil.pojo.getProperty(o2, field);
if (value1 != null && value2 != null) {
if (value1 instanceof Long) {
return ((Long) value1).compareTo((Long) value2) * direction;
}
if (value1 instanceof Integer) {
return ((Integer) value1).compareTo((Integer) value2) * direction;
}
if (value1 instanceof Double) {
return ((Double) value1).compareTo((Double) value2) * direction;
}
if (value1 instanceof BigDecimal) {
return ((BigDecimal) value1).compareTo((BigDecimal) value2) * direction;
}
if (value1 instanceof Date) {
return ((Date) value1).compareTo((Date) value2) * direction;
}
if (value1 instanceof String) {
return ((String) value1).compareTo((String) value2) * direction;
}
}
return 0;
}
});
}
/**
* 除重
*
* @param src
* @param <K>
* @return
*/
public static <K> List<K> distinct(List<K> src) {
if (ValidateUtil.isEmpty(src)) {
return src;
}
return new ArrayList<K>(src.stream().collect(Collectors.toSet()));
}
}