我使用以下代码生成包含数据的图表:
@GetMapping("/terminals")
public ResponseEntity<Map<String, List<TopTerminalsDTO>>> getTopTerminals(
@RequestParam(value = "start_date", required = true) String start_date,
@RequestParam(value = "end_date", required = true) String end_date) {
final List<PaymentTransactionsDailyFacts> list = dashboardService.findTop_Terminals(start_dateTime, end_dateTime);
final Collector<PaymentTransactionsDailyFacts, List<TopTerminalsDTO>, List<TopTerminalsDTO>> terminalsCollector = Collector
.of(ArrayList::new, (terminals, p) -> terminals.add(mapper.toTopTerminalsDTO(p)),
(accumulator, terminals) -> {
accumulator.addAll(terminals);
return accumulator;
});
final Map<String, List<TopTerminalsDTO>> final_map = list.stream().filter(p -> p.getTerminal_id() != null)
.collect(Collectors.groupingBy(p -> getTerminalName(p.getTerminal_id()), terminalsCollector));
return ResponseEntity.ok(final_map);
}
private String getTerminalName(Integer id) {
Optional<Terminals> obj = terminalService.findById(id);
return obj.map(Terminals::getName).orElse("");
}
但是我注意到getTerminalName
被叫了10次以上,以从数字转换名字。您知道如何通过一些优化来减少通话次数吗?
答案 0 :(得分:2)
修改findTop_Terminals
和PaymentTransactionsDailyFacts
以包括名称(使用SQL LEFT JOIN
子句)。
或者,在列表中扫描所有终端ID,然后调用List<Terminals> list = terminalService.findByIds(idList);
方法以使用SQL IN
子句获取所有这些终端。
注意:注意SQL语句中可以包含多少个?
标记。
然后构建一个Map<Integer, String>
映射终端ID到名称,并将getTerminalName
方法替换为地图查找。
答案 1 :(得分:1)
听起来像是临时缓存的情况,范围仅限于此请求,或者如果终端名称足够稳定,则可能更长。
很显然,像幕后的ehCache之类的东西很适合此操作,但是我经常对战术性的缓存很感兴趣,特别是如果我不想将缓存的值保留在此即时请求之外。
例如:
TerminalNameCache cache = new TerminalNameCache();
final Map<String, List<TopTerminalsDTO>> final_map = list.stream()
.filter(p -> p.getTerminal_id() != null)
.collect(Collectors.groupingBy(
p -> cache.getTerminalName(p.getTerminal_id()),
terminalsCollector));
然后TerminalNameCache
只是父Controller类中的一个内部类。这是为了允许它从问题中调用现有的private String getTerminalName(Integer id)
方法(如下面的ParentControllerClass
所示):
private class TerminalNameCache {
private final Map<Integer, String> cache = new ConcurrentHashMap<>();
private String getTerminalName(Integer id) {
return cache.computeIfAbsent(id,
id2 -> ParentControllerClass.this.getTerminalName(id2));
}
}
如果这看起来已成为一种模式,则值得将缓存重构为更可重用的内容。例如。这可以基于对通用函数的缓存调用:
public class CachedFunction<T, R> implements Function<T, R> {
private final Function<T, R> function;
private final Map<T, R> cache = new ConcurrentHashMap<>();
public CachedFunction(Function<T, R> function) {
this.function = function;
}
@Override
public R apply(T t) {
return cache.computeIfAbsent(t, t2 -> function.apply(t2));
}
}
然后将这样使用:
CachedFunction<Integer, String> cachedFunction = new CachedFunction<>(
id -> getTerminalName(id));
final Map<String, List<TopTerminalsDTO>> final_map = list.stream()
.filter(p -> p.getTerminal_id() != null)
.collect(Collectors.groupingBy(
p -> cachedFunction.apply(p.getTerminal_id()),
terminalsCollector));