Redis实现点赞与关注
Redis:支持数据类型完善;使用简单;性能好;Redis是一款基于键值对的NoSQL数据库,对于Redis数据库保存的键值对来说,键总是一个字符串对象,而值可以是字符串对象、列表对象、哈希对象、集合对象或有序集合对象:String, hashes, Lists, Sets, Sorted Sets.
Redis将所有的数据都存放在内存中,所以他的读写性能十分惊人;(性能)
同时,Redis还可以将内存中的数据以快照或日志的形式保存到硬盘上,以保证数据的安全性。(安全性)
其中:快照的形式:RDB的形式,直接把内存的数据存到硬盘上,优点是数据体积小,如果想从硬盘恢复到内存速度快;缺点是比较耗时,做存储的时候可能会产生阻塞,此时在处理其他的业务会影响其他的业务。不适合实时去做,可以几小时做一次的那种;日志的方式:AOF:每执行一个Redis命令就以日志的形式存下来,可以做到实时的存;但是以不断的追加的形式存的,体积较大,占用磁盘空间,且恢复的时候是把存的命令从头到尾再跑一遍,恢复的速度较慢;
访问Redis:
redisTemplate.opsForValue()
redisTemplate.opsForHash()
redisTemplate.opsForList()
redisTemplate.opsForSet()
redisTemplate.opsForZSet()
@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
可以参考Bean重写序列化:https://blog.youkuaiyun.com/lichuangcsdn/article/details/80866253
@Configuration
public class RedisConfig {
/*
* @Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一
* 个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext
* 或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
* */
//实际上,Spring很好的实现了泛型依赖注入<String, Object>
// https://blog.youkuaiyun.com/f641385712/article/details/84679147
/*
* StringRedisTemplate与RedisTemplate的区别
两者的关系是StringRedisTemplate继承RedisTemplate。
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,
RedisTemplate只能管理RedisTemplate中的数据。
默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
* */
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//定义一个bean,方法名为redisTemplate;当声明了这个bean方法,
// 参数为RedisConnectionFactory,参数也是一个Bean,它会被自动注入进来,被容器装配
//都配好后,就可以通过redisTemplate访问redis了
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);//template具有了访问数据库的能力
//写Java程序得到Java类型数据是要存到数据库中,所以要指定一种数据转化的方式
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// value本身为hash时:设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();//触发生效
return template;
}
}
点赞点踩:访问非常频繁;就是一个数量,这样的数据存放到关系型数据的表里,也不方便存储;
RedisKeyUtil类:定义String类型的Key
public class RedisKeyUtil {
private static final String SPLIT = ":";
private static final String PREFIX_ENTITY_LIKE = "like:entity";
private static final String PREFIX_USER_LIKE = "like:user";
private static final String PREFIX_FOLLOWEE = "followee";
private static final String PREFIX_FOLLOWER = "follower";
private static final String PREFIX_KAPTCHA = "kaptcha";
private static final String PREFIX_TICKET = "ticket";
private static final String PREFIX_USER = "user";
private static final String PREFIX_UV = "uv";
private static final String PREFIX_DAU = "dau";
private static final String PREFIX_POST = "post";
//定义一个静态方法
// 某个实体的赞
// like:entity:entityType:entityId -> set(userId)
public static String getEntityLikeKey(int entityType, int entityId) {
return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId;
}
//某个用户所获得的赞的总数,这里是key的格式,value为总数
//like:user:userId->int
public static String getUserLikeKey(int userId){
return PREFIX_USER_LIKE + SPLIT + userId;
}
// 某个用户关注的实体:有序集合,以时间为序
// followee:userId:entityType -> zset(entityId,now)
public static String getFolloweeKey(int userId, int entityType) {
return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType;
}
// 某个实体拥有的粉丝
// follower:entityType:entityId -> zset(userId,now)
public static String getFollowerKey(int entityType, int entityId) {
return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId;
}
// 登录验证码: kaptcha:owner 其中ower为用户的一个临时凭证
//每一个key都不同,对应的value为验证码
public static String getKaptchaKey(String owner) {
return PREFIX_KAPTCHA + SPLIT + owner;
}
// 登录的凭证: kaptcha:ticket
public static String getTicketKey(String ticket) {
return PREFIX_TICKET + SPLIT + ticket;
}
// 用户 kaptcha:userId
public static String getUserKey(int userId) {
return PREFIX_USER + SPLIT + userId;
}
// 单日UV
public static String getUVKey(String date) {
return PREFIX_UV + SPLIT + date;
}
// 区间UV
public static String getUVKey(String startDate, String endDate) {
return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;
}
// 单日活跃用户
public static String getDAUKey(String date) {
return PREFIX_DAU + SPLIT + date;
}
// 区间活跃用户
public static S