【Redis】论坛项目中Redis知识点汇总

1 Redis入门

在这里插入图片描述Redis优点:性能很好、支持的数据很完善、使用简单
Redis应用:
1.缓存:使用非常频繁的数据,可以放在内存上
2.排行榜:访问非常频繁的帖子,放在内存上
3.计数器:每访问一下帖子,浏览量+1,这个动作很频繁,用Redis实现
4.社交网络:点赞、点踩、关注,动作很频繁,这种数据存在数据库里也不好存,以键值对的方式存在内存里
5.消息队列:可以满足要求,但不是专门的

Redis主要学数据类型,会存数据类型就ok了,用各种命令

官网:https://redis.io/
在这里插入图片描述

下载win版:https://github.com/microsoftarchive/redis
管理员cmd

redis-cli
select 1#内置16个库
flushdb#不想要数据了,刷新库,把内容刷没
#Redis里两个相连的单词用:隔开
set test:count 1#存String类型数据
get test:count
incr test:count#+1
decr test:count#-1
hset test:user id 1#存Hash类型数据
hget test:user id
#list数据:横向容器,左进右出,有序
lpush test:ids 101 102 103
llen test:ids
lindex test:ids 0
lrange test:ids 0 2
rpop test:ids
#集合:无序,无重复数据
sadd test:teachers aaa bbb ccc ddd eee
scard test:teachers#统计
spop test:teachers#随机弹出一个数据
smembers test:teachers
#有序集合:给每个存的值附加一个分数,用分数排序
zadd test:students 10 aaa 20 bbb 30 ccc
zscore test:students ccc#查分数
zrank test:students ccc
zrange test:students 0 2

keys *
keys test*
type test:user
exists test:user
del test:user
expire test:students 10#有效期10秒

2 Spring整合Redis

在这里插入图片描述

#RedisProperties
spring.redis.database=11
spring.redis.host=localhost
spring.redis.port=6379
@Configuration
public class RedisConfig {
    @Bean//定义第三方Bean,Bean名字为redisTemplate
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){//注入连接工厂才能链接数据库
        RedisTemplate<String,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);//可以访问数据库了
        //设置key的序列化方式
        template.setKeySerializer(RedisSerializer.string());
        //设置value的序列化方式
        template.setValueSerializer(RedisSerializer.json());
        //设置hash的key的序列化方式
        template.setHashKeySerializer(RedisSerializer.string());
        //设置hash的value的序列化方式
        template.setHashValueSerializer(RedisSerializer.json());

        template.afterPropertiesSet();//设置完之后,触发生效
        return template;
    }
}


@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTests {

    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    public void testStrings(){
        String redisKey = "test:count";
        redisTemplate.opsForValue().set(redisKey, 1);

        System.out.println(redisTemplate.opsForValue().get(redisKey));
        System.out.println(redisTemplate.opsForValue().increment(redisKey));
        System.out.println(redisTemplate.opsForValue().decrement(redisKey));
    }

    @Test
    public void testHash(){
        String redisKey = "test:user";

        redisTemplate.opsForHash().put(redisKey, "id", 1);
        redisTemplate.opsForHash().put(redisKey,"username","zhangsan");

        System.out.println(redisTemplate.opsForHash().get(redisKey, "id"));
        System.out.println(redisTemplate.opsForHash().get(redisKey, "username"));
    }

    @Test
    public void testLists(){
        String redisKey = "test:ids";

        redisTemplate.opsForList().leftPush(redisKey, 101);
        redisTemplate.opsForList().leftPush(redisKey, 102);
        redisTemplate.opsForList().leftPush(redisKey, 103);

        System.out.println(redisTemplate.opsForList().size(redisKey));
        System.out.println(redisTemplate.opsForList().index(redisKey, 0));
        System.out.println(redisTemplate.opsForList().range(redisKey, 0, 2));

        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
    }

    @Test
    public void testSets() {
        String redisKey = "test:teachers";

        redisTemplate.opsForSet().add(redisKey,"刘备","关羽","张飞");

        System.out.println(redisTemplate.opsForSet().size(redisKey));
        System.out.println(redisTemplate.opsForSet().pop(redisKey));
        System.out.println(redisTemplate.opsForSet().members(redisKey));
    }

    @Test
    public void testSortedSets() {
        String redisKey = "test:students";

        redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);
        redisTemplate.opsForZSet().add(redisKey, "悟空", 90);
        redisTemplate.opsForZSet().add(redisKey, "八戒", 70);

        System.out.println(redisTemplate.opsForZSet().zCard(redisKey));
        System.out.println(redisTemplate.opsForZSet().score(redisKey,"八戒"));
        System.out.println(redisTemplate.opsForZSet().rank(redisKey,"八戒"));
        System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey,"八戒"));
    }

    @Test
    public void testKeys() {
        redisTemplate.delete("test:user");
        System.out.println(redisTemplate.hasKey("test:uesr"));

        redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);
    }

    //多次访问同一个key
    @Test
    public void testBoundOperations(){
        String redisKey = "test:count";
        //BoundxxxOperations中间是访问的数据类型
        BoundValueOperations operations = redisTemplate.boundValueOps(redisKey);
        //对比之前:redisTemplate.opsForValue().increment(redisKey)
        operations.increment();
        System.out.println(operations.get());
    }

    //编程式事务
    //启动事务之后,后面的Redis命令并不会立即执行,而是把命令放在队列里,提交事务时批量执行
    //所以不要在事务里查询,要在事务提交后查询
    @Test
    public void testTransactional(){
        Object obj = redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String redisKey = "text:tx";
                operations.multi();//启动事务
                operations.opsForSet().add(redisKey,"zhangsan");
                operations.opsForSet().add(redisKey,"lisi");
                System.out.println(operations.opsForSet().members(redisKey));
                operations.opsForSet().add(redisKey,"wangwu");
                System.out.println(operations.opsForSet().members(redisKey));
                return operations.exec();//提交事务
            }
        });
        System.out.println(obj);
    }
}

注意最后几行的事务:

查询一定要放在事务之外

redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String redisKey = "text:tx";
                operations.multi();//启动事务
                operations.opsForSet().add(redisKey,"zhangsan");
                operations.opsForSet().add(redisKey,"lisi");
                System.out.println(operations.opsForSet().members(redisKey));
                operations.opsForSet().add(redisKey,"wangwu");
                System.out.println(operations.opsForSet().members(redisKey));
                return operations.exec();//提交事务
            }
        });

3 点赞

在这里插入图片描述
点赞是个很频繁的动作,将点赞存到redis里提高性能。核心是对redis的使用

向Redis存数据、取数据,操作数据的过程中,是以key为关键的
为了让key反复复用,要写一个工具专门生成key

3.1 生成Key的工具RedisKeyUtil

public class RedisKeyUtil {
    //简单工具不需要由容器管理,提供静态方法就行了
    private static final String SPLIT = ":";
    private static final String PREFIX_ENTITY_LIKE = "like:entity";

    //某个实体的赞
    //like:entity:entityType:entityId  谁给实体点赞,userId存入entityLikeKey对应的set里
    public static String getEntityLikeKey(int entityType,int entityId){
        return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId;
    }
}

3.2 编写Service

@Service
public class LikeService {
    @Autowired
    private RedisTemplate redisTemplate;

    //点赞
    public void like(int userId, int entityType, int entityId){
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
        if(isMember){
            redisTemplate.opsForSet().remove(entityLikeKey, userId);
        }else{
            redisTemplate.opsForSet().add(entityLikeKey, userId);
        }
    }

    //查询某实体被点赞的数量
    public long findEntityLikeCount(int entityType, int entityId){
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().size(entityLikeKey);
    }

    //查询某人对某实体的点赞状态
    //此处返回整数,使程序更有扩展性,比如:以后会出点踩功能
    public int findEntityLikeStatus(int userId, int entityType, int entityId){
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().isMember(entityLikeKey, userId)?1:0;
    }
}

3.3 编写Controller

点赞:点的时候是异步请求,整个页面不刷新,点完之后改变状态就行了
用map封装返回的结果,返回JSON格式的字符串

@RequestMapping(path = "/like",method = RequestMethod.POST)
    @ResponseBody
    public String like(int entityType,int entityId){
        User user = hostHolder.getUser();
        //点赞
        likeService.like(user.getId(), entityType, entityId);
        //数量
        long likeCount = likeService.findEntityLikeCount(entityType, entityId);
        //状态
        int likeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId);
        //用map封装返回的结果
        Map<String, Object> map = new HashMap<>();
        map.put("likeCount", likeCount);
        map.put("likeStatus", likeStatus);
        //返回JSON格式的字符串
        return CommunityUtil.getJSONString(0, null, map);
    }

3.4 修改动态页面中对帖子点赞的显示

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值