Redis-实战案例

资料来源 极客时间 Redis 亚风 原文视频:https://u.geekbang.org/lesson/535?article=681063

需求一 :帖子

同⼀个⽤户只能点赞⼀次,再次点击则取消点赞
如果当前⽤户已经点赞,则点赞按钮⾼亮实现
展示点赞数量并展示点赞top3(时间)的⽤户信息

@RestController
public class BlogController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 博客点赞功能,不需要排行榜
     * @param userID
     * @param blogID
     * @return
     */
    @GetMapping("/likeBlog")
    public String likeBlog(String userID, String blogID) {
        String key = "blog" + ":" + blogID;
        Boolean member = stringRedisTemplate.opsForSet().isMember(key, userID);
        if (Boolean.TRUE.equals(member)) {
            System.out.println("已点赞,取消点赞");
            stringRedisTemplate.opsForSet().remove(key, userID);
        } else {
            System.out.println("没有点赞,进行点赞");
            stringRedisTemplate.opsForSet().add(key, userID);
        }
       return "OK";
    }
    /**
     * 博客点赞功能,需要排行榜
     * @param userID
     * @param blogID
     * @return
     */
    @GetMapping("/likeBlogTop")
    public String likeBlogTop(String userID, String blogID) {
        String key = "blog" + ":" + blogID;
        Double score = stringRedisTemplate.opsForZSet().score(key, userID);
        if (Objects.nonNull(score)) {
            System.out.println("已点赞,取消点赞");
            stringRedisTemplate.opsForZSet().remove(key, userID);
        } else {
            System.out.println("没有点赞,进行点赞");
            // 时间 越靠前 得分越多
            stringRedisTemplate.opsForZSet().add(key, userID, System.currentTimeMillis());
        }
        return "OK";
    }

    /**
     * 博客点赞功能,返回top3
     * @param userID
     * @param blogID
     * @return
     */
    @GetMapping("/getBlog")
    public Blog getBlog(String blogID, String userID) {
        String key = "blog" + ":" + blogID;
        Long count = stringRedisTemplate.opsForZSet().size(key);
        Blog blog = new Blog();
        blog.setBlogID(blogID);
        blog.setLikeCount(count);
        blog.setIsLike(Objects.nonNull(stringRedisTemplate.opsForZSet().score(key, userID)) );
        Set<String> likeUsers = stringRedisTemplate.opsForZSet().range(key, 0, 2);
        blog.setLikeUsers(likeUsers);
        return blog;
    }
}

需求二 : 附近的人或者商店

GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加⼊了对GEO的⽀持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。 其原理是geohash
GEOADD:添加⼀个地理空间信息,包含:经纬度、值
GEODIST:计算指定的两个点之间的距离并返回
GEOHASH:将指定member的坐标转为hash字符串形式并返回
GEOPOS:返回指定member的坐标
GEORADIUS:指定圆⼼、半径,找到该圆内包含的所有member,并按照与圆⼼之间的距离排序后返回。6.2以后已废弃。
GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2新功能。
geohash 相关知识

@RestController
public class GeoController {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 就算距离
     * @param x
     * @param y
     * @return
     */
    @RequestMapping("radius")
    @ResponseBody
    public List<GeoResult<RedisGeoCommands.GeoLocation<String>>> radius(double x, double y){
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                .limit(5)
                //包含成员距离中心点的距离
                .includeDistance();

        GeoResults<RedisGeoCommands.GeoLocation<String>> result = stringRedisTemplate.opsForGeo().radius("near",
                new Circle(new Point(x,y),new Distance(10000, Metrics.KILOMETERS)),args);
        return result.getContent();
    }

    /**
     * 添加地理坐标系
     * @return
     */
    @RequestMapping("putLongLat")
    public String  putLongLat() {
        double x = 130.5423;
        double y = 30.54235;
        String key = "near";
        String member;
        for (int i = 0; i < 5; i ++) {
            x += i * 0.01;
            y += i * 0.01;
            member = "po" + i;
            stringRedisTemplate.opsForGeo().add(key, new Point(x, y), member);
        }
        return "OK";
    }
}

需求三:签到

把每⼀个bit位对应当⽉的每⼀天,形成了映射关系。⽤0和1标示业务状态,这种思路就称为位图(BitMap),Redis中是利⽤string类型数据结构实现BitMap,因此最⼤上限是512M,转换为bit则是 2^32 个bit位。
BitMap的操作命令有:
SETBIT:向指定位置 (offset)存⼊⼀个0或1
GETBIT:获取指定位置 (offset)的bit值
BITCOUNT:统计 BitMap中值为1的bit位的数量
BITFIELD:操作(查询、修改、⾃增) BitMap中bit数组中的指定位置
(offset)的值
BITFIELD_RO:获取BitMap中bit数组,并以⼗进制形式返回
BITOP:将多个BitMap的结果做位运算(与、或、异或)
BITPOS:查找bit数组中指定范围内第⼀个0或1出现的位置

@RestController
public class SignController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @RequestMapping("sign")
    @ResponseBody
    public  String sign(String userId) {
        LocalDateTime now = LocalDateTime.now();
        String key= "sign:"+userId+ ":"+now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        // 将当天的位变为 1
        stringRedisTemplate.opsForValue().setBit(key,now.getDayOfMonth()-1,true);
        return "SUCCESS";
    }

    @RequestMapping("signCount")
    @ResponseBody
    public Long signCount(String userId) {
        LocalDateTime now = LocalDateTime.now();
        String key= "sign:"+userId+ ":"+now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.
                unsigned(now.getDayOfMonth())).valueAt(0));
        if(CollectionUtils.isEmpty(result)){
            return 0L;
        }
        Long num = result.get(0);
        // 统计连续签到数量
        Long count = 0L;
        while(true){
            if((num&1)==0){
                break;
            }else{
                count++;
            }
            num >>>=1;
        }
        return count;
    }
}

需求四:UV统计

UV:全称Unique Visitor,也叫独⽴访客量,是指通过互联⽹访问、浏览这个⽹⻚的⾃然⼈。1天内同⼀个⽤户多次访问该⽹站,只记录1次。
PV:全称Page View,也叫⻚⾯访问量或点击量,⽤户每访问⽹站的⼀个⻚⾯,记录1次PV,⽤户多次打开⻚⾯,则记录多次PV。往往⽤来衡量⽹站的流量。
Hyperloglog(HLL)是从Loglog算法派⽣的概率算法,⽤于确定⾮常⼤的集合的基数,⽽不需要存储其所有值。
Redis中的HLL是基于string结构实现的(不允许出现相同元素),单个HLL的内存永远⼩于16kb,作为代价,其测量结果是概率性的,有⼩于0.81%的误差。不过对于UV统计来说,这完全可以忽略。

PFADD key element | [elements] #也就是支持数组 #命令用于将一个或多个元素添加到 HyperLogLog 中。如果 HyperLogLog 不存在,该命令将创建一个新的 HyperLogLog。如果 HyperLogLog已经存在,它将更新估计的基数。
PFCOUNT key | [keys] #也支持数组 #PFCOUNT 是 Redis 中用于获取 HyperLogLog(基数估计算法)数据结构的估计基数(不同元素的数量)的命令。该命令用于返回给定 HyperLogLog 的近似基数,即集合中的不同元素数量的估计值。
PFMERGE destkey sourcekey [sourcekey...] #合并key

你可能感兴趣的:(数据库,redis,bootstrap,数据库,redis,实战)