接口的多线程查询
这里的问题的主要是,当客户想要一年的统计数据的时候,往往会因为数据量太大而导致统计信息出不了。
也没啥办法,除非又弄个什么es同步,统计信息走bi啥的。麻烦死了。正常来说,数据同步不应该走数据库的binlog同步吗,不知道为什么,好像我们这里走的不是。所以好像同步都是bi那边一页一页的捞。
先不管他,这里反正我们限制了查询只有1年时间,那很容易就想到,能不能5天查。然后都统计上去。
能不能改成多线程。
if(businessCenterConfig.costBillDetailSummarySplit()){
String billDateStart = costBillDto.getBillDateStart();
String billDateEnd = costBillDetailDto.getBillDateEnd();
String moduleCode = request.getHeader("module_code");
if (StringUtils.isBlank(costBillDto.getPageSourceCode())) {
costBillDto.setPageSourceCode(moduleCode);
}
String cloumn="d.bill_date";
if (costBillDetailDto.getBillDateType() != null && Objects.equals(costBillDetailDto.getBillDateType(), FinByteConstant.ONE)) {
cloumn="t.bill_date";
}
long days = DateUtils.getDaysBetween(DateUtils.strToDateLong(billDateStart), DateUtils.strToDateLong(billDateEnd));
int interval=5;
TemporalUnit unit= ChronoUnit.DAYS;
List<TimeInterval> timeIntervals = DateUtils.calculateTimeIntervals(DateUtils.dateToLocalDateTime(billDateStart), DateUtils.dateToLocalDateTime(billDateEnd), interval, unit);
int size = timeIntervals.size();
String finalCloumn = cloumn;
MemberInfo memberInfo = MemberHolder.getMemberInfo();
Long loggerSn = CommonContextHolder.getLoggerSn();
List<CostBillDetail> costBillDetailList = IntStream.range(0, size).parallel().mapToObj(i -> {
boolean isLast = i == size - 1;
TimeInterval v = timeIntervals.get(i);
CommonContextHolder.setLoggerSn(loggerSn);
MemberHolder.bindMember(memberInfo);
String dateStrat = DateUtils.dateToString(DateUtils.localDateTimeTodate(v.getStartTime()), "yyyy-MM-dd HH:mm:ss");
String dateEnd = DateUtils.dateToString(DateUtils.localDateTimeTodate(v.getEndTime()), "yyyy-MM-dd HH:mm:ss");
CostBillDetailDTO costBillDetailDTO = new CostBillDetailDTO();
BeanUtil.copyProperties(costBillDetailDto, costBillDetailDTO);
costBillDetailDTO.setBillDateStart(dateStrat);
costBillDetailDTO.setBillDateEnd(dateEnd);
SearchCondition searchCondition = this.buildSeacchGetAllDetail(costBillDetailDTO, costBillDto);
if (!isLast) {
searchCondition = SearchConditionUtil.clearConditonByColumn(searchCondition, "bill_date");
SearchConditionUtil searchConditionUtil = new SearchConditionUtil();
searchConditionUtil.andGreaterThanOrEqualTo(searchCondition, finalCloumn, dateStrat);
searchConditionUtil.andLessThan(searchCondition, finalCloumn, dateEnd);
}
CostBillDetail details = costBillDao.getDetailSummary(searchCondition);
return details;
}).collect(Collectors.toList());
CostBillDetail costBillDetail = costBillDetailList.stream().reduce((a, b) -> {
b.setBaseAmount(a.getBaseAmount().add(b.getBaseAmount()));
b.setTranAmount(a.getTranAmount().add(b.getTranAmount()));
b.setHasNoTaxBaseAmount(a.getHasNoTaxBaseAmount().add(b.getHasNoTaxBaseAmount()));
b.setHasNoTaxTranAmount(a.getHasNoTaxTranAmount().add(b.getHasNoTaxTranAmount()));
return b;
}).orElse(null);
return costBillDetail;
}else{
SearchCondition searchCondition = this.buildSeacchGetAllDetail(costBillDetailDto,costBillDto);
CostBillDetail details = costBillDao.getDetailSummary(searchCondition);
return details;
}
结果就出来了这么一版代码,开白名单,给客户试用。
白名单的客户走多线程的统计,里面按5天间隔去查,
因为between是等价于>=和<=,所以我们想等价替换的话,需要时间间隔先
用>=和<来替换between,最后一个间隔还是between。用IntStream来获取到对应的次序,从而判断是否最后一个。
这里还有一个坑的是,用parallel()的时候,注意查询条件不要公用一个对象,因为可能线程紊乱。还有的话就是多线程,因为没有上下文信息,记得赋值下上下文信息,不然mybatis的查询日志不是同一个logId。
还有一个问题,查询条件用到了request,但是异步线程拿不到request的,还是上下文的问题,但是不想赋值了,于是就提到异步线程外了。