Redis教程

【Redis实战】:1、初始Redis

本文主要是介绍【Redis实战】:1、初始Redis,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

【GitHub】:示例代码
【GitHub】:redis-plus-plus

1、Redis简介

1、Redis与其他数据库和软件对比

名称类型数据存储选项查询类型附加功能
Redis内存存储的非关系数据库字符串、列表、集合、散列表、有序集合各数据类型均有专属命令,另外还有批量操作和不完全的事务支持发布与订阅,主从复制,持久化,脚本 [存储过程]
memcached内存存储的键值缓存键值之间的映射创建、读取、更新、删除以及其他几个命令为提升性能而设的多线程服务器
MySQL关系数据库1数据库可含n表,1表可含n行;可处理n表的视图;支持空间和第三方扩展SELECT、DELETE、INSERT、UPDATE、函数、存储过程支持ACID性质 [需用lnnoDB],主从复制和主主复制
PostgreSQL关系数据库1数据库可含n表,1表可含n行;可处理n表的视图;支持空间和第三方扩展;支持可定制类型SELECT、INSERT、UPDATE、DELETE、内置函数、自定义的存储过程支持ACID性质,主从复制,由第三方支持的多主复制
MongoDB硬盘存储的非关系文档存储1数据库可含n表,1表可含n无schema的BSONÄ档创建、读取、更新、删除、条件查询等支持map-reduce操作,主从复制,分片,空间索引

Redis与memcached异同:均可存键值映射,前者自动写硬盘有两种方式,支持更多类型,可主可辅


2、附加特性

内存数据库经典问题:服务器关闭时,存储的数据去向
Redis持久化:1、时间点转储 2、所有修改命令追加至文件
主存复制特性:从服务器获取主服务器初始副本,之后靠修改命令持续更新,客户端可读任意从服务器


3、使用Redis理由

1、数据存内存,请求无需经查询分析器或查询优化器处理【随机写快】
2、避免操作临时数据

2、Redis数据结构简介

数据结构类型:STRING [字符串]、LIST [列表]、SET [集合]、HASH [散列] 和 ZSET [有序集合]

结构类型结构存储的值结构的读写能力
STRING字符串、整数、浮点数操作字符串整体或者部分;自增或自减整数和浮点数
LIST链表,表上各节点均含一字符串链表两端可推或弹元素;根据偏移量修剪链表;读取1…n个元素;根据值查找或者移除元素
SET含字符串的无序收集器,且被包含的各字符串均不相同添加、获取丶移除单个元素;检查一元素是否在集合中;计算交集、并集丶差集;从集合里随机获取元素
HASH含键值对的无序散列表添加、获取丶移除单个键值对;获取所有键值对
ZSET [有序集合]字符串成员与浮点数分值之间的有序映射,元素的排序由分值大小决定添加、获取、删除单个元素;根据分值范围或成员来获取元素

1、Redis中的字符串
在这里插入图片描述

命令行为
get获取存储在给定键中的值
set设置存储在给定键中的值
del删除存储在给定键中的值 [可用于所有类型]
// 字符串命令操作:
redis-cli -h 192.168.86.3 -a 123456
set hello world	 // set执行成功返ok
get hello	// 获取hello键中的值
del hello	// 删键值对,返成功删除数
get hello	// 键已不存在, 返nil
quit

在这里插入图片描述


2、Redis中的列表
在这里插入图片描述

命令行为
rpush将给定值推入列表的右端
lrange获取列表在给定范围上的所有值
lindex获取列表在给定位置上的单个元素
lpop从列表的左端弹出一个值,并返回被弹出的值
redis-cli -h 192.168.86.3 -a 123456
rpush list-key item
rpush list-key item2
rpush list-key item3	// 向列表推入新元素之后, 该命令会返回列表当前的长度

lrange list-key 0 -1	// 使用0为范围的起始索引,-1为范围的结束索引,可以取出列表包含的所有元素
lindex list-key 1

lpop list-key	// 从列表里面弹出一个元素, 被弹出的元素将不再存在于列表
lrange list-key 0 -1

在这里插入图片描述


3、Redis中的集合
在这里插入图片描述

命令行为
sadd将给定元素添加到集合
smembers返回集合包含的所有元素
sismember检查给定元素是否存在于集合中
srem如果给定的元素存在于集合中,那么移除这个元素
sadd set-key item
sadd set-key item2
sadd set-key item3
sadd set-key item	// 返1添加成功, 返0则失败

smembers set-key	// 元素多时会很慢, 慎用
sismember set-key item4		// 检查某元素是否在集合中
sismember set-key item

srem set-key item2	// 返回被移除元素数
srem set-key item2

smembers set-key

在这里插入图片描述


4、Redis中的散列
在这里插入图片描述

命令行为
hset在散列里面关联起给定的键值对
hget获取指定散列键的值
hgetall获取散列包含的所有键值对
hdel如果给定键存在于散列里面,那么移除这个键
hset hash-key sub-key1 value1
hset hash-key sub-key2 value2
hset hash-key sub-key1 value1	// 返0表示键已存在

hgetall hash-key

hdel hash-key sub-key2
hdel hash-key sub-key2	// 返0表示键不在散列里

hget hash-key sub-key1
hgetall hash-key

在这里插入图片描述


5、Redis中的有序集合
在这里插入图片描述

命令行为
zadd将一个带有给定分值的成员添加到有序集合里
zrange根据元素在有序排列中所处的位置,从有序集合里面获取多个元素
zrangebyscore获取有序集合在给定分值范围内的所有元素
zrem如果给定成员存在于有序集合,那么移除这个成员
zadd zset-key 728 member1
zadd zset-key 982 member0
zadd zset-key 982 member0

zrange zset-key 0 -1 withscores	// 元素按分值大小排序
zrangebyscore zset-key 0 800 withscores	// 根据分值获取部分元素

zrem zset-key member1
zrem zset-key member1	// 返0表示键不在有序集合里

zrange zset-key 0 -1 withscores

在这里插入图片描述

3、Redis处理文章业务
#pragma once
#include <cstdio>
#include <iostream>
#include <list>
#include <string>
#include <tr1/unordered_map>
#include <set>
#include <assert.h>

#include <sw/redis++/redis++.h>

using namespace sw::redis;

class chapter_01
{
private:
    static const int ONE_WEEK_IN_SECONDS = 7 * 86400;
    static const int VOTE_SCORE = 432;
    static const int ARTICLES_PER_PAGE = 25;

public:
    void run()
    {
        // Create an Redis object, which is movable but NOT copyable.
        auto redis = Redis("tcp://123456@192.168.86.3:6379");

        auto article_id = post_article(
            redis, "username", "A title", "http://www.google.com"); // 发布文章:作者,标题,链接
        std::cout << "We posted a new article with id: " + article_id << std::endl;
        std::cout << "Its HASH looks like:" << std::endl;

        std::unordered_map<std::string, std::string> article_data;
        redis.hgetall("article:" + article_id,      // Hash, return key-vals
            std::inserter(article_data, article_data.begin()));     // 获取文章散列中所有信息
        for (auto& item : article_data)
        {
            std::cout << "  " + item.first + ": " 
                + item.second << std::endl;
        }

        std::cout << std::endl;

        article_vote(redis, "other_user", "article:" + article_id); // 对文章投票,用户第一次投增票数和评分
        auto votes = redis.hget("article:" + article_id, "votes").value();  // Hash, return val     // 获取文章散列中票数
        std::cout << "We voted for the article, it now has votes: " + votes << std::endl;
        assert(atoi(votes.c_str()) > 1);

        std::cout << "The currently highest-scoring articles are:" << std::endl;
        auto articles = get_articles(redis, 1); // 获取第1页按评分排序的文章
        print_articles(articles);   // 打印文章
        assert(articles.size() >= 1);

        add_groups(redis, article_id, std::vector<std::string>{ "new-group" }); // 将所投文章加入某分组
        std::cout << "We added the article to a new group, other articles include:" << std::endl;
        articles = get_group_articles(redis, "new-group", 1);   // 获取该分组所有文章
        print_articles(articles);
        assert(articles.size() >= 1);
    }

    // 发布并获取文章
    std::string post_article(sw::redis::Redis& redis,
        std::string user,
        std::string title,
        std::string link)
    {
        std::string article_id = std::to_string(redis.incr("article:"));    // 生成新文章ID

        std::string voted = "voted:" + article_id;
        redis.sadd(voted, user);    // set, add key     // 将用户加入文章投票名单
        redis.expire(voted, ONE_WEEK_IN_SECONDS);       // 设一周过期

        auto now = time(NULL) / 1000;
        std::string article = "article:" + article_id;
        std::unordered_map<std::string, std::string> article_data;
        article_data.insert({ "title", title });
        article_data.insert({ "link", link });
        article_data.insert({ "user", user });
        article_data.insert({ "now", std::to_string(now) });
        article_data.insert({ "votes", "1" });
        redis.hmset(article, article_data.begin(), article_data.end());     // Hash, create hash

        redis.zadd("score:", article, static_cast<double>(now + VOTE_SCORE));    // sorted set, add key-val  // 加入评分排序的有序集合
        redis.zadd("time:", article, static_cast<double>(now));  // 加入时间排序的有序集合

        return article_id;
    }

    // 对文章投票
    void article_vote(sw::redis::Redis& redis, std::string user, std::string article)
    {
        auto cutoff = (time(NULL) / 1000) - ONE_WEEK_IN_SECONDS;    // 计算文章投票截止时间
        auto ob = redis.zscore("time:", article).value();   // sorted set, return val
        if (ob < static_cast<double>(cutoff))    // 检查是否还可对文章投票 [有序集合相较散列返浮点数, 可不用转换]
            return;

        std::string article_id = article.substr(article.find_first_of(':') + 1);    // 从article:id标识符里取出文章ID
        if (redis.sadd("voted:" + article_id, user) == 1)   // set, add key     // 第一次投票, 则增加投票数和评分
        {
            redis.zincrby("score:", VOTE_SCORE, article);   // sorted set, +increment
            redis.hincrby(article, "votes", 1);     // Hash, +increment
        }
    }

    // 获取某页内所有文章
    std::list<std::unordered_map<std::string, std::string>>
        get_articles(sw::redis::Redis& redis, int page)
    {
        return get_articles(redis, page, "score:");
    }

    // 获取某页内所有文章
    std::list<std::unordered_map<std::string, std::string>>
        get_articles(sw::redis::Redis& redis, int page, std::string order)
    {
        int start = (page - 1) * ARTICLES_PER_PAGE;     // 设置文章起始索引和结束索引
        int end = start + ARTICLES_PER_PAGE - 1;

        std::set<std::string> ids;
        redis.zrevrange(order, start, end, std::inserter(ids, ids.end()));  // sorted set, val-desc, return range-keys  // 获取该页众文章ID
        std::list<std::unordered_map<std::string, std::string>> articles;
        for (std::string id : ids)
        {
            std::unordered_map<std::string, std::string> article_data;
            redis.hgetall(id, std::inserter(article_data, article_data.begin()));  // Hash, return key-vals // 根据文章ID获取文章详细信息
            article_data.insert({ "id", id });
            articles.push_back(article_data);
        }

        return articles;
    }

    // 对文章进行分组
    void add_groups(sw::redis::Redis& redis, std::string article_id, std::vector<std::string> toAdd)
    {
        std::string article = "article:" + article_id;
        for (auto& item : toAdd)
        {
            redis.sadd("group:" + item, article);   // set, add key     // 将文章加入所属群组 
        }
    }

    // 获取分组中某页文章
    std::list<std::unordered_map<std::string, std::string>> get_group_articles(
        sw::redis::Redis& redis,
        std::string group,
        int page)
    {
        return get_group_articles(redis, group, page, "score:");
    }

    std::list<std::unordered_map<std::string, std::string>> get_group_articles(
        sw::redis::Redis& redis,
        std::string group,
        int page,
        std::string order)
    {
        std::string key = order + group;    // 为每个群组的每种排列顺序创键
        if (!redis.exists(key))     // 检查是否有缓存结果,无则排
        {
            redis.zinterstore(key, { "group:" + group, order }, sw::redis::Aggregation::MAX);   // sorted set   // 根据评分或时间对文章排序
            redis.expire(key, 60);  // set key expiration time  // 60秒过期,自动删
        }
        return get_articles(redis, page, key);  // 获取该页内所有文章
    }

    void print_articles(std::list<std::unordered_map<std::string, std::string>> articles)
    {
        for (auto article : articles)
        {
            std::cout << "  id: " + article["id"];
            for (auto& item : article)
            {
                if (!item.first.compare("id"))
                {
                    continue;
                }
                std::cout << "    " + item.first + ": " + item.second << std::endl;
            }
        }
    }
};

在这里插入图片描述

这篇关于【Redis实战】:1、初始Redis的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!