Java实现一定时间内同时请求接口时返回相同数据
1. 缓存机制
使用本地缓存(如Caffeine)
@Service
public class DataService {
private final Cache<String, Object> cache = Caffeine.newBuilder()
.expireAfterWrite(30, TimeUnit.SECONDS) // 30秒过期
.maximumSize(1000)
.build();
public Object getData(String key) {
return cache.get(key, k -> fetchDataFromSource(k));
}
private Object fetchDataFromSource(String key) {
// 实际的数据获取逻辑
return new Object();
}
}
使用Redis缓存
@Service
public class DataService {
@Autowired
private StringRedisTemplate redisTemplate;
public Object getData(String key) {
String cachedData = redisTemplate.opsForValue().get(key);
if (cachedData != null) {
return JSON.parseObject(cachedData, Object.class);
}
// 获取新数据
Object data = fetchDataFromSource(key);
redisTemplate.opsForValue().set(key, JSON.toJSONString(data), 30, TimeUnit.SECONDS);
return data;
}
}
2. 请求合并机制
使用ConcurrentHashMap实现请求合并
@Service
public class MergingDataService {
private final ConcurrentHashMap<String, CompletableFuture<Object>> pendingRequests = new ConcurrentHashMap<>();
public CompletableFuture<Object> getDataAsync(String key) {
// 检查是否有正在进行的相同请求
CompletableFuture<Object> existingFuture = pendingRequests.get(key);
if (existingFuture != null) {
return existingFuture;
}
// 创建新的请求
CompletableFuture<Object> newFuture = new CompletableFuture<>();
CompletableFuture<Object> previousFuture = pendingRequests.putIfAbsent(key, newFuture);
if (previousFuture != null) {
// 其他线程已经创建了请求
return previousFuture;
}
// 执行实际的数据获取
try {
Object data = fetchDataFromSource(key);
newFuture.complete(data);
return newFuture;
} finally {
pendingRequests.remove(key);
}
}
private Object fetchDataFromSource(String key) {
// 实际的数据获取逻辑
return new Object();
}
}
3. 控制器层实现
@RestController
public class DataController {
@Autowired
private DataService dataService;
@Autowired
private MergingDataService mergingDataService;
@GetMapping("/data")
public ResponseEntity<Object> getData(@RequestParam String key) {
try {
Object data = dataService.getData(key);
return ResponseEntity.ok(data);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@GetMapping("/data/async")
public CompletableFuture<ResponseEntity<Object>> getDataAsync(@RequestParam String key) {
return mergingDataService.getDataAsync(key)
.thenApply(data -> ResponseEntity.ok(data))
.exceptionally(throwable -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build());
}
}
4. 使用Spring Cache注解
@Service
@EnableCaching
public class CachedDataService {
@Cacheable(value = "dataCache", key = "#key", unless = "#result == null")
@Cacheable(cacheNames = "dataCache", key = "#key")
public Object getData(String key) {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return fetchDataFromSource(key);
}
private Object fetchDataFromSource(String key) {
return new Object();
}
}
推荐方案
- 简单场景:使用本地缓存或Redis缓存
- 高并发场景:使用请求合并机制避免重复计算
- 复杂业务:结合多种方案,先检查缓存,再进行请求合并
这样可以有效减少重复请求对后端服务的压力,并保证在缓存有效期内返回相同的数据。

浙公网安备 33010602011771号