对于给定的请求,例如/api/user/1
,假设从数据库中查询将花费10s。
因此,首先,服务器接受了一个请求,该服务开始查询数据库。然后在查询期间,可能会有更多传入的相同请求(全部用于/api/user/1
)。
如何避免以后的请求查询数据库?我们并不是说缓存,我们只是想避免完全相同的查询同时发生。
这有意义吗?如果是,该如何做(以Java或节点应用程序为例)?
答案 0 :(得分:0)
您可以使用"/api/user/1"
(请参阅here),该映射将List
之类的路由字符串映射到T
的回调,这些回调采用单个T
类型的参数(将request
替换为用于存储请求结果的任何类)。您的Consumer<T>
方法将需要使用Consumer<T>
进行回调。如果您不熟悉T
,则可以阅读有关here的信息。它只是表示一个函数的接口,该函数采用一个register
类型的参数,但不返回任何内容。
当线程希望将请求的结果发送给路由时,应调用同步方法String
,该方法将路由作为Map
和回调并执行以下操作:
它应该检查路由是否是Map
中的键。如果不是,则应将路由作为关键字添加到List
,其值应为resolve
,其中包含一个值,参数中提供了回调,然后应使用我将在下面讨论方法Map
的回调。如果路由已经是List
中的键,那么只需将线程的回调添加到Map
中的resolve
中,其中路由是键。
String
函数应将路由视为T
,并将请求结果键入List
。然后,它将在路由键处获取Map
,从public abstract class CallbackHandler<T> {
private QueryRepetitionHandler<T> handler;
private CountDownLatch latch;
private T result;
public CallbackHandler(QueryRepetitionHandler<T> handler) {
this.handler = handler;
latch = new CountDownLatch(1);
}
public void resolve(T result) {
this.result = result;
latch.countDown();
}
public void request(String route) {
handler.register(route);
latch.await();
}
}
中删除路由键,最后遍历所有回调并使用请求结果对其进行调用。
我已经用示例编写了一些代码,但是我没有对其进行测试。
CallbackHandler.java
public abstract class QueryRepetitionHandler<T> {
private Map<String, List<CallbackHandler<T>> map = new ConcurrentHashMap<>();
protected abstract void request(String route, Consumer<T> consumer);
public synchronized void register(String route, CallbackHandler<T> handler) {
if (map.containsKey(route)) {
map.get(route).add(callback);
} else {
List<CallbackHandler<T>> list = new ArrayList<>();
list.add(callback);
map.put(route, list);
request(route, result -> resolve(route, result));
}
}
private void resolve(String route, T result) {
List<Consumer<T>> list = map.remove(route);
// Sanity check
if (list != null) {
list.forEach(handler -> handler.resolve(result));
}
}
}
QueryRepetitionHandler.java
QueryRepetitionHandler<T>
您将要实例化一个CallbackHandler<T>
,以供所有线程共享。当线程想要发出请求时,应使用共享的QueryRepetitionHandler<T>
实例化QueryRepetitionHandler<T>
。当然,如果不实现request
方法,就无法实例化request
。 Consumer<T>
方法应该简单地发出请求,然后调用作为request
提供的回调。然后,它应使用所需的路由作为CallbackHandler<T>
参数来调用String
的{{1}}方法。然后,该线程将等待(使用latch.await()
)请求的结果,直到QueryRepetitionHandler<T>
调用带有结果的resolve
方法并调用latch.countDown()
为止。