目录
项目背景:
数据汇总访问时间长的问题:
解决方案:
1.创建参与访问表
2.使用redis进行优化
总结:
项目背景:
一个简单的抽奖系统,当要统计每天的参与访问,总的参与访问
数据汇总访问时间长的问题:
每次访问都会遍历整个订单表进行查询,当数据库数据多的时候会对数据库造成压力,也会更加耗时,初始查询20秒
解决方案:
新建一张数据汇总表,例如拿总参与,总访问,每日参与,每日访问来说,遍历订单表查询是不太合理的,会占用大量的系统资源,可以利用redis的缓存递增来做,将一些数据临时放入redis里面,数据汇总的时候在持久化到mysql数据库中
1.创建参与访问表
sql语句:
CREATE TABLE `sb_access_count` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`created` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`access_count` int DEFAULT NULL COMMENT '当日访问量',
`user_count` int NOT NULL DEFAULT '0' COMMENT '当天参与量',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
① 创建参与访问表,作为日数据的保存,每次访问我们的接口都在这个表里面累加1
但是每次访问我们的接口,都会对数据库造成吃就会,也会对数据库造成压力,不合理,这里我们可以用redis进行优化
2.使用redis进行优化
①将每日参与访问保存至redis
定义一个固定的Key加上当日的时间作为redis的key,value的值为每日的参与和访问,第一次访问的时候先查询一下看redis里面是否有值,没有的话就是存进去,然后是1,如果有值就redis缓存递增1
public void activityDayAccessCount(String itemCode) {
ActivityDO activityDO = activityDao.getActivityByCode(itemCode);
if (activityDO == null) {
logger.info("增加每日访问数量,查询不到该活动= " + itemCode);
return;
}
RedisUtils redisUtils = MyApplicationContext.getBean(RedisUtils.class);
Date date = new Date();
String time = DateUtils.datePathyyyymmdd(date);
//活动访问key
String accessesKey = itemCode + MyConstant.DAY_ACCESSES + time;
Integer sum = (Integer) redisUtils.get(accessesKey);
if (sum == null) {
int expireTime = 2 * 24 * 60 * 60;
redisUtils.set(accessesKey, 1, expireTime);
} else {
//缓存递增
redisUtils.incr(accessesKey, 1);
}
}
②持久化到数据库
有两种情况下会持久化到数据库
第一种:写一个定时任务,每天定时持久化到数据库
第二种:点击数据汇总的时候调用此方法,将redis最新的数据拉取到本地,在进行数据汇总
public void task() {
logger.info("参与访问数据落库========>");
Date date = new Date();
String time = DateUtils.datePathyyyymmdd(date);
String acessKey = MyConstant.ACCESS_SUM_KEY + time;
String userCanyuKey = MyConstant.PARTICIPAT_SUM_KEY + time;
System.out.println("acessKey = " + acessKey);
System.out.println("userCanyuKey = " + userCanyuKey);
Integer accessCount = (Integer) redisUtils.get(acessKey);
System.out.println("accessCount = " + accessCount);
Integer userCount = (Integer) redisUtils.get(userCanyuKey);
System.out.println("userCount = " + userCount);
Date dayStart = DateUtils.getDayStart(date);
Date dayEnd = DateUtils.getDayEnd(date);
QueryWrapper<AccessCountDO> queryWrapper = new QueryWrapper();
queryWrapper.ge("created", dayStart);
queryWrapper.le("created", dayEnd);
AccessCountDO accessCountDO = accessCountMapper.selectOne(queryWrapper.orderByDesc("id").last("limit 1"));
if (accessCountDO == null) {
accessCountDO = new AccessCountDO();
if (accessCount == null) {
accessCountDO.setAccessCount(0);
} else {
accessCountDO.setAccessCount(accessCount);
}
if (userCount == null) {
accessCountDO.setUserCount(0);
} else {
accessCountDO.setUserCount(userCount);
}
accessCountMapper.insert(accessCountDO);
} else {
accessCountDO.setAccessCount(accessCount);
accessCountDO.setUserCount(userCount);
accessCountMapper.updateById(accessCountDO);
}
}
以上方法不用每次都查询订单表,尤其是订单表数据量过大的时候会很耗时,给用户造成不好的体验
总结:
需要善用redis,redis作为缓存数据库性能非常高,尽量不要与mysql数据库进行交互,把一些非实时的数据缓存至redis,查询效率非常高!