上上下下左右左右BABA 哈哈 我有三十条命了,我是正在学Java的张三
求个关注!求个点赞!!学习不容易,你点赞我才有动力继续学习下去啊!
今天讲一讲张三学习Redis中遇到的问题哈,大家看文章都会发现文章有个阅读量,阅读量这个数据呢,重要性不是很高,但也是一个衡量文章优秀程度的指标嘛。
张三一下子就想到了解决办法,这个简单,那我访问一次就把阅读量+1嘛!
一、利用Redis的incr方法,每访问一次加一
Redis Incr 命令将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
@Aspect
@Component
public class BlogViewAspect {
@Autowired
private RedisUtils redisUtils;
@Autowired
private StringRedisTemplate redisTemplate;
/*
* execution:切到文章controller层的查询一条的方法上,
* args:方法的参数,文章的id
* redis的键:"viewCount:" + id
*/
@Before(value = "execution(* com.xxx.xxx.controller.BlogController.findOne(..)) && args(id)")
public void dealView(String id) {
String key = "viewCount:" + id;
redisTemplate.opsForValue().increment(key);
}
}
复制代码
张三突然想到,要是有人恶意刷访问量的啊!该咋解决呢?
张三,
本来发量不多的张三在抠掉了几个头发之后,想到了我可以把访问的ip记录下嘛,有这个ip的话就不让他加访问量撒;
Redis的key不是可以用冒号分割吗,那我用viewCount:文章id:ip作为键撒,统计的时候就用keys viewCount:id:*
得到他的个数就是他的访问量嘛
张三想到这儿,赶紧删掉之前的代码,重新写了起来!
二、Redis利用冒号命名空间的形式实现访问量
@Aspect
@Component
public class BlogViewAspect {
@Autowired
private RedisUtils redisUtils;
@Autowired
private StringRedisTemplate redisTemplate;
/*
* execution:切到文章controller层的查询一条的方法上,
* args:方法的参数,id:文章的id,request:HttpServletRequest
* redis的键:viewCount:id:ip
*/
@Before(value = "execution(* com.xxx.xxx.controller.BlogController.findOne(..)) && args(id, request)")
public void dealView(String id, HttpServletRequest request) {
String ip = IpUtil.getIp(request);
String key = "viewCount:" + id + ":" + ip;
redisTemplate.opsForValue().set(key, 1);
}
}
获取文章访问量
redisTemplate.keys("viewCount:" + id + ":*").size()
复制代码
写完之后,跑到楼下来了根华子,,心里默念到:”我TM真是个人才”;
回到电脑面前,张三突然想到,那这样的话访问量多了咋整哦,n个不同的文章,每个文章一万个不同的ip访问,就生成n*10000
个key,Redis 能存这么多的key吗!
我去,没考虑到啊,,emmmmm……..,那我就用viewCount:id
作为key,每次访问往这个set里面加ip,反正set可以去重嘛,直接往里面加就行了,也不用判断啥的,然后取访问量的话直接用SCARD viewCount:id
就可以得到嘛!
赶紧删掉刚刚的代码,重写!
三、Redis利用Set实现访问量
@Aspect
@Component
public class BlogViewAspect {
@Autowired
private StringRedisTemplate redisTemplate;
/*
* execution:切到文章controller层的查询一条的方法上,
* args:方法的参数,id:文章的id,request:HttpServletRequest
* redis的键:viewCount:id
*/
@Before(value = "execution(* com.xxx.xxx.controller.BlogController.findOne(..)) && args(id, request)")
public void dealView(String id, HttpServletRequest request) {
String ip = IpUtil.getIp(request);
String key = "viewCount:" + id
redisTemplate.opsForSet().add(key, ip);
}
}
获取文章访问量
redisTemplate.opsForSet().size("viewCount:" + id);
复制代码
刚刚写完,张三又想到,set存数据不也得占用内存吗,虽然这样做key的数量降下来了,但是和刚刚一样,每个文章一万个不同的ip访问,那你这个文章的set里面是不是就要存一万个ip呢?
靠,这内存怕不也要被耗完哦!
就没其他可以使用少量内存就可以进行统计的办法了吗????难道我张三就这么菜吗???这样还怎么成为高富帅,怎么迎娶白富美!!!
赶紧查阅资料
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
这不就是我想要的吗,啊哈哈哈!
还是用viewCount:id
,但是用HyperLogLog来统计,每次把ip输进去不就行了!我TM真是个人才
再改代码!
四、利用HyperLogLog实现访问量统计
@Aspect
@Component
public class BlogViewAspect {
@Autowired
private StringRedisTemplate redisTemplate;
/*
* execution:切到文章controller层的查询一条的方法上,
* args:方法的参数,id:文章的id,request:HttpServletRequest
* redis的键:viewCount:id
*/
@Before(value = "execution(* com.xxx.xxx.controller.BlogController.findOne(..)) && args(id, request)")
public void dealView(String id, HttpServletRequest request) {
String ip = IpUtil.getIp(request);
String key = "viewCount:" + id
redisTemplate.opsForHyperLogLog().add(key, ip);
}
}
获取文章访问量
redisTemplate.opsForHyperLogLog().size("viewCount:" + id);
复制代码
感谢各位和张三一样在学习的路上的点赞,关注!!!!!
要一直在路上啊!!
上上下下左右左右BABA 哈哈 我有三十条命了,我是正在学Java的张三,欢迎关注