继上一篇继续优化内容.
-
将排行榜缓存改为按日期存储,查看的时候可以根据日期查看当天的数据
hscan的时候查询参数改为"*:“+type+”:"+time 就能获取指定日期的数据了
然后存入的时候携带日期就行了 hset 的fieId为 username:time -
根据id获取username的操作 原本是每次循环都根据id去数据库查,优化后是在循环前查出所有用户,然后存入map里 key=id value=username 然后循环的时候去map里取用户名 减少了mysql的多次查询操作
新需求既然是更具指定时间查数据,就没有汇总的操作,其实可以不用新的的字段存储汇总的数据作为缓存了 可以直接取原字段数据展示出来的.
以下代码是两个改动的方法
@Scheduled(cron = "0 0 0/1 * * ? ")//一个小时执行一次
public void getTrafficRankByDay(){
LogUtils.info("==============redis更新用户使用流量排行开始=================");
try {
String today = DateUtil.today();//获取当天日期
long start = System.currentTimeMillis();
List<SysUser> sysUsers = userMapper.selectAll();
Map<String, String> map = new HashMap<>();
for (SysUser user :
sysUsers) {
map.put(user.getId(), user.getUserName());
}
Map<String, String> trafficRank = userService.getTrafficRankByDay(1,today,map);//动态住宅
Map<String, String> trafficRankjf = userService.getTrafficRankByDay(2,today,map);//海外机房住宅
Map<String, String> gtrafficRank4g = userService.getTrafficRankByDay(3,today,map);//4G住宅
JedisUtil.hmset(SysConstants.TRAFFIC_RANK,trafficRank);
JedisUtil.hmset(SysConstants.TRAFFIC_RANK_JF,trafficRankjf);
JedisUtil.hmset(SysConstants.TRAFFIC_RANK_4G,gtrafficRank4g);
long end = System.currentTimeMillis();
LogUtils.info("==============redis更新用户使用流量排行成功共耗时"+ (end - start) +"毫秒=================");
} catch (Exception e) {
e.printStackTrace();
LogUtils.info("==============更新redis用户流量排行榜失败=================");
}
}
public Map<String, String> getTrafficRankByDay(Integer type,String time,Map<String, String> userMap){
// String newTime = replaceLast(time,"*");//将日期的最后一天改为* 只查询每个月01-09 10-19 20-29 30-31的数据
//redis存的格式是 dbc1649c-d8d2-4808-af02-5736cbc66ada:1:2022-05-12 -> 流量
HashMap<String, String> map = new HashMap<>();
HashMap<String, String> userNameMap = new HashMap<>();
long start = System.currentTimeMillis();
Map<String, String> redisMap = JedisUtil.getAll("userFlowCounter", 50000,"*:"+type+":"+time);//
long end = System.currentTimeMillis();
System.err.println("=======================redis查询共耗时" + (end - start) + "毫秒=====================");//输出程序运行时间
Set<String> keys = redisMap.keySet(); //此行可省略,直接将map.keySet()写在for-each循环的条件中
//遍历redis的结果, 过滤key 只保留userId 和日流量再存入新的map里
for(String key:keys){
//截取:之前的userId
String userId = StringUtils.substringBefore(key, ":");
//判断map集合中有没有这个userId为名字的key
//containsKey返回值为boolean类型
//日流量
BigDecimal userBillByDay = new BigDecimal(redisMap.get(key));
if(map.containsKey(userId)){
//根据key取出value再加上name相同的另一个参数的value
BigDecimal mapBill = new BigDecimal(map.get(userId));
BigDecimal addBill = userBillByDay.add(mapBill);//相加之后的流量
map.put(userId,addBill.toString());
}
else{
map.put(userId,userBillByDay.toString());
}
}
Set<String> userName = map.keySet(); //获取用户名
for(String key:userName){//先过滤:type: 指定类型的结果 1为动态2为海外机房3为4G
// SysUser byId = userMapper.getById(key);
//userMap 是userId:userName的结构
if(ObjectUtil.isNotNull(userMap.get(key))){
userNameMap.put(userMap.get(key)+":"+time,map.get(key));
}else {
userNameMap.put(key+":"+time,map.get(key));
}
}
// Map<String, String> stringDoubleMap = sortMapByValue(userNameMap); 不排序 因为存入redis的时候又无序了 接口取数据的时候重新排序就行了
return userNameMap;
}