设计需求是记录数据集的每日访问量,可以进行趋势查看。
最简单的就是直接每次操作记录日志,然后在查询时直接根据日志使用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;
/**
* 更新访问量:即时更新数据集表的访问量,更新redis中存储的当前访问量;然后在定时器中每晚更新日期访问表中的量
*/
public void visitDataset(Long datasetId, int Source) {
// 更新数据集表的数量
String redisKey = "dset_v_" + datasetId;
stringRedisTemplate.opsForValue().increment(redisKey);
// 给哪个数据集的哪个字段加1
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() {
// 先更新日期;然后重新写入
// 查出所有数据集的id,遍历查找当前访问量,按当前日期插入数据库
List<Long> ids = datasetProjectMapper.getIds();
LocalDate now = LocalDate.now();
for (Long item : ids) {
// 查redis,并按当前日期插入
String redisKey = "dset_v_" + item;
Object rv = stringRedisTemplate.opsForValue().get(redisKey);
// if (rv == null) {
// redisTemplate.opsForValue().set(redisKey, 0);
// }
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");
}
}
}
以上由于时间问题暂未处理失败补偿