1. 缓存
String类型
例如:热点数据缓存、对象缓存、全页缓存可以提升热点数据的访问效率
2. 数据共享分布式
String类型,因为redis是分布式的独立服务,可以在多个应用服务之间共享,例如分布式session
1 | <dependency> |
3. 分布式锁
String类型 setnx方法,只有不存在时才能添加成功返回true
1 | public static boolean getLock(String key) { |
4. 全局ID
int 类型, incrby, 利用原子性
1 | incrby userid 1000 |
分库分表的场景,一次性拿一段。
5. 计数器
int 类型,incr方法
例如:文章的阅读量、微博点赞数;允许一定的延迟,先写入redis在定时同步到数据库
第一种方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class TestService {
RedisTemplate<String,Object> redisTemplate;
private ValueOperations<String,Object> ops;
public int testRedis() {
try {
//此方法会先检查key是否存在,存在+1,不存在先初始化,再+1
ops.increment("success", 1);
//return (int) ops.get("success"); //使用这个会出现错误,报错信息 Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.EOFException。
return Integer.valueOf(redisTemplate.boundValueOps("success").get(0, -1));
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return 0 ;
}
}第二种方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class TestService {
RedisTemplate<String,Object> redisTemplate;
private ValueOperations<String,Object> ops;
public int testRedis() {
try {
//此方法会先检查key是否存在,存在+1,不存在先初始化,再+1
ops.increment("success", 1);
//return (int) ops.get("success");
//return Integer.valueOf(redisTemplate.boundValueOps("success").get(0, -1));
return (int) getKey("success");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return 0 ;
}
public long getKey(final String key) {
return redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> redisSerializer = redisTemplate.getStringSerializer();
byte[] rowkey = redisSerializer.serialize(key);
byte[] rowval = connection.get(rowkey);
try {
String val = redisSerializer.deserialize(rowval);
return Long.parseLong(val);
} catch (Exception e) {
return 0L;
}
}
});
}
}设置每天零点过期,重新计数
1
2
3
4
5
6
7//当天时间
Date date = new Date();
//当天零点
date = DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
//第二天零点
date = DateUtils.addDays(date, +1);
redisTemplate.expireAt("success", date);6. 限流
int类型,incr方法
以访问者的IP和其他信息作为key,访问一次增加一次次数,超过次数 则返回false
7. 位统计
String类型的bitcount
字符是以8位二进制存储的
1 | set k1 a |
例如:在线用户统计,留存用户统计
1 | setbit onlineusers 01 |
支持按位与、按位或等等操作
1 | BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。 |
计算出7天都在线的用户
1 | BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users" |
8. 购物车
String 或hash。所有String可以做的hash都可以
hash类型是一个String类型的field和value的映射表,每个hash都可以存储2^32 -1键值对
使用hash做购物车:以用户id为key, 商品id为field,商品数量为value。
9. 用户消息时间线timeline
list,双向链表,直接作为timeline就好了。插入有序
10. 消息队列
List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间
blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低队列:先进先除:rpush blpop,左头右尾,右边进入队列,左边出队列
栈:先进后出:rpush brpop
11. 抽奖
自带一个随机获得值
1 | spop myset |
12. 点赞、签到、打卡
假如上面的微博ID是t1001,用户ID是u3001
用 like:t1001 来维护 t1001 这条微博的所有点赞用户
- 点赞了这条微博:sadd like:t1001 u3001
- 取消点赞:srem like:t1001 u3001
- 是否点赞:sismember like:t1001 u3001
- 点赞的所有用户:smembers like:t1001
- 点赞数:scard like:t1001
13. 商品标签
用 tags:i5001 来维护商品所有的标签。
- sadd tags:i5001 画面清晰细腻
- sadd tags:i5001 真彩清晰显示屏
- sadd tags:i5001 流程至极
14.商品筛选
1 | // 获取差集 |
1 | sadd brand:apple iPhone11 |
筛选商品,苹果的、ios的、屏幕在6.0-6.24之间的,屏幕材质是LCD屏幕
1 | sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd |
15. 用户关注、推荐模型
1 | # follow 关注 fans 粉丝 |
我关注的人也关注了他(取交集):
1 | sinter 1:follow 2:fans |
可能认识的人:
1 | # 用户1可能认识的人(差集): |
16. 排行榜
id 为6001 的新闻点击数加1:zincrby hotNews:20190926 1 n6001
获取今天点击最多的15条:zrevrange hotNews:20190926 0 15 withscores
redis不适用的场景
Redis是一种缓存技术,主要用来提高应用的性能,更多的应用场景是对数据库读数据进行缓存,减轻数据库的IO的访问压力,以下场景不太适合使用Redis:
数据规模大小角度
Redis是将数据放在内存进行缓存的,内存相对于磁盘来锁价格是比较贵的。如果成本是需要考虑的重要因素,那么大规模的数据就不太适合;
数据冷热程度角度
很多业务数据可以根据数据读的频繁程度分为热数据和冷数据;频繁使用的热数据一般适合用redis,冷数据一般不太适合用redis,如果大量的冷数据进行了缓存,那是对内存资源的浪费,
所以在应用场景上区分冷热数据,将热数据放在内存中,进而提高性能。