设计需求是记录数据集的每日访问量,可以进行趋势查看。
最简单的就是直接每次操作记录日志,然后在查询时直接根据日志使用sql实时统计。这种方案很简单,不需要另外考虑存储结构,只要查询语句写好即可。但是对于数据量稍微大一些的场景,这种方式的效率将会非常差。 因此这里考虑将每日访问量在数据库中存储下来,然后查询的时候能直接查即可。
思路就是设计表将数据集、日期共同作为复合主键,存储访问量数据。 由于在这个表中设计每人访问加1,直接更新这个表的话代价会比较大
sql表结构
CREATE TABLE `g_dataset_visit_count` (
`dataset_id` bigint(11) NOT NULL COMMENT '数据集id',
`v_date` datetime NOT NULL COMMENT '日期',
`v_count` int(255) DEFAULT NULL COMMENT '访问量',
`type` tinyint(4) DEFAULT NULL COMMENT '类型:1、数据页访问;2、接口查询',
PRIMARY KEY (`dataset_id`,`v_date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
使用redis进行计数
@Resource
StringRedisTemplate stringRedisTemplate;
@Autowired
DatasetProjectMapper datasetProjectMapper;
public void visitDataset(Long datasetId, int Source) {
String redisKey = "dset_v_" + datasetId;
stringRedisTemplate.opsForValue().increment(redisKey);
datasetProjectMapper.pageVisitIncre(datasetId, Source);
}
定时任务持久化
@Component
@EnableScheduling
public class DatasetVisitInitJob {
@Resource
StringRedisTemplate stringRedisTemplate;
@Autowired
DatasetProjectMapper datasetProjectMapper;
@Autowired
DatasetVisitCountMapper datasetVisitCountMapper;
@Scheduled(cron = "0 30 23 * * ?")
public void createHyperLog() {
List<Long> ids = datasetProjectMapper.getIds();
LocalDate now = LocalDate.now();
for (Long item : ids) {
String redisKey = "dset_v_" + item;
Object rv = stringRedisTemplate.opsForValue().get(redisKey);
DatasetVisitCount dvc = new DatasetVisitCount();
try {
dvc.setVCount(Integer.parseInt(rv.toString()));
} catch (Exception e) {
dvc.setVCount(0);
}
dvc.setDatasetId(item);
dvc.setVDate(now);
dvc.setType(1);
datasetVisitCountMapper.insert(dvc);
Object c = stringRedisTemplate.opsForValue().getAndSet(redisKey, "0");
}
}
}
以上由于时间问题暂未处理失败补偿
|