-->

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();
    }
}

推荐方案

  1. 简单场景:使用本地缓存或Redis缓存
  2. 高并发场景:使用请求合并机制避免重复计算
  3. 复杂业务:结合多种方案,先检查缓存,再进行请求合并

这样可以有效减少重复请求对后端服务的压力,并保证在缓存有效期内返回相同的数据。

posted @ 2025-11-13 10:25  ꧁ʚ星月天空ɞ꧂  阅读(4)  评论(0)    收藏  举报