最近我们项目有个统计实时库存的接口,数据量过大导致每次调用都超时,导致页面一片空白。
为了不影响使用,我将库存信息存到一张新的表里面,通过定时任务定时计算更新库存。同时也可以让用户异步的去手动更新实时库存。这样也不影响用户在前端页面查看。
那么如果是异步更新的话,如果同一个用户同时点击多次,该怎么去避免呢?
首先我的接口代码:
@GetMapping("refresh-inventory")
@ApiOperation("一健刷新实时库存")
public ResultDto<ProjectCurrentInventoryDto> refreshInventory() {
ResultDto resultDto = new ResultDto();
try{
String userId = SecurityUserHolder.getCurrentUserId();
List<Integer> projectIds = manageService.queryCompanyIdByUser(userId);
//异步方法
tahGoodsService.setSemaphore(userId, projectIds);
resultDto.setData("刷新中.....");
}catch (Exception e){
resultDto.setError("操作失败");
e.printStackTrace();
}
return resultDto;
}
setSemaphore是一个异步方法,具体代码如下:
// Init on startup
// Key should be a unique identifier to a company, I assume the `String company` as key, you should adjust as your real requirement
static final Map<String, Semaphore> COMPANY_ENTRANT = new ConcurrentHashMap<>();
/**
* 防止重复点击刷新
* @param userId
* @param projectIds
*/
@Async
@Override
public void setSemaphore(String userId, List<Integer> projectIds){
Semaphore entrant = COMPANY_ENTRANT.putIfAbsent(userId, new Semaphore(1));
if(entrant==null){
COMPANY_ENTRANT.put(userId, new Semaphore(1));
entrant = COMPANY_ENTRANT.get(userId);
}
try{
entrant.acquire();
//计算实时库存
updateCurrentInventory(projectIds);
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
entrant.release();
}
}