Redis in action 读书记录01 redis的一些常用命令

Redis 数据结构

  • String: 字符串
  • Hash: 散列
  • List: 列表
  • Set: 集合
  • Sorted Set: 有序集合

Redis常用命令

string字符串常用命令
字符串get、set、del命令

命令

行为

GET

获取存储在给定键中的值

SET

设置存储在给定键中的值

DEL

删除存储在给定键中的值

字符串中的自增命令和自减命令

命令

行为

INCR

INCR key-name 将键存储的值加上1

DECR

DECR key-name 将键存储的值减去1

INCRBY

INCRBY key-name amount 将键存储的值加上整数amount

DECRBY

DECRBY key-name amount 将键存储的值减去整数amount

INCRBYFLOAT

INCRBYFLOAT key-name amount 将键存储的值加上浮点数amount

当用户将一个值存储到 Redis 字符串里面的时候,如果这个值可以被解释(interpret)为十 进制整数或者浮点数,那么 Redis 会察觉到这一点,并允许用户对这个字符串执行各种 INCR和DECR操作。如果用户对一个不存在的键或者一个保存了空串的键执行自增或者自减操作,那么Redis 在执行操作时会将这个键的值当作是 0 来处理。如果用户尝试对一个值无法被解释为整数或者浮点数的字符串键执行自增或者自减操作,那么 Redis 将向用户返回一个错误。代码清单 3-1展示了对字符串执行自增操作和自减操作的一些例子。

字符串处理子串和二进制位的命令

命令

用例和描述

APPEND

APPEND key-name value 将值value追加到给定键key-name当前存储的值的末尾

GETRANGE

GETRANGE key-name start end 获取一个由偏移量start至偏移量end范围内所有字符组成的子串,包括start和end在内

SETRANGE

SETRANGE key-name offset value—将从 start 偏移量开始的子串设置为给定值

GETBIT

GETBIT key-name offset—将字节串看作是二进制位串(bit string),并返回位串中偏移量为offset 的二进制位的值

SETBIT

SETBIT key-name offset value—将字节串看作是二进制位串,并将位串中偏移量为 offset的二进制位的值

BITCOUNT

BITCOUNT key-name [start end]—统计二进制位串里面值为 1 的二进制位的数量,如果给定了可选的 start 偏移量和 end 偏移量,那么只对偏移量指定范围内的二进制位进行统计

BITOP

BITOP operation dest-key key-name [key-name …]—对一个或多个二进制位串执行包括并(AND)、或 (OR)、异或(XOR)、非 (NOT)在内的任意一种按位运算操作(bitwise operation),

Redis Desktop Manager 汉化教程 redis in action中文版_redis

Redis Desktop Manager 汉化教程 redis in action中文版_偏移量_02

list列表常用命令

命令

行为

RPUSH

RPUSH key-name value [value …]—将一个或多个值推入列表的右端

LRANGE

LPUSH key-name value [value …]—将一个或多个值推入列表的左端

LINDEX

LINDEX key-name offset—返回列表中偏移量为 offset 的元素

LPOP

LPOP key-name—移除并返回列表最左端的元素

RPOP

RPOP key-name—移除并返回列表最右端的元素

LRANGE

LRANGE key-name start end—返回列表从 start 偏移量到 end 偏移量范围内的所有元素,其中偏移量为 start 和偏移量为 end 的元素也会包含在被返回的元素之内

LTRIM

LTRIM key-name start end—对列表进行修剪,只保留从 start 偏移量到 end 偏移量范围内的元素,其中偏移量为 start 和偏移量为 end 的元素也会被保留

BLPOP

BLPOP key-name [key-name …] timeout—从第一个非空列表中弹出位于最左端的元素,或者在 timeout 秒之内阻塞并等待可弹出的元素出现

BRPOP

BRPOP key-name [key-name …] timeout—从第一个非空列表中弹出位于最右端的元素,或者在 timeout 秒之内阻塞并等待可弹出的元素出现

RPOPLPUSH

RPOPLPUSH source-key dest-key—从 source-key 列表中弹出位于最右端的元素,然后将这个元素推入 dest-key 列表的最左端,并向用户返回这个元素

BRPOPLPUSH

BRPOPLPUSH source-key dest-key timeout—从 source-key 列表中弹出位于最右端的元素,然后将这个元素推入 dest-key 列表的最左端,并向用户返回这个元素;如果 source-key为空,那么在 timeout 秒之内阻塞并等待可弹出的元素出现

Redis Desktop Manager 汉化教程 redis in action中文版_redis_03

Redis Desktop Manager 汉化教程 redis in action中文版_字符串_04

set集合常用命令

命令

行为

SADD

SADD key-name item [item …]—将一个或多个元素添加到集合里面,并返回被添加元素当中原本并不存在于集合里面的元素数量

SMEMBERS

SISMEMBER key-name item—返回集合包含的所有元素

SISMEMBER

SMEMBERS key-name—检查给定元素是否存在于集合中

SREM

SREM key-name item [item …]—从集合里面移除一个或多个元素,并返回被移除元素的数量

SCARD

SCARD key-name—返回集合包含的元素的数量

SRANDMEMBER

SRANDMEMBER key-name [count]—从集合里面随机地返回一个或多个元素。当 count为正数时,命令返回的随机元素不会重复;当 count 为负数时,命令返回的随机元素可能会出现重复

SPOP

SPOP key-name—随机地移除集合中的一个元素,并返回被移除的元素

SMOVE

SMOVE source-key dest-key item—如果集合 source-key 包含元素 item,那么从集合 source-key 里面移除元素 item,并将元素 item 添加到集合 dest-key 中;如果 item被成功移除,那么命令返回 1,否则返回 0

SDIFF

SDIFF key-name [key-name …]—返回那些存在于第一个集合、但不存在于其他集合中的元素(数学上的差集运算)

SDIFFSTORE

SDIFFSTORE dest-key key-name [key-name …]—将那些存在于第一个集合但并不存在于其他集合中的元素(数学上的差集运算)存储到 dest-key 键里面

SINTER

SINTER key-name [key-name …]—返回那些同时存在于所有集合中的元素(数学上的交集运算)

SINTERSTORE

SINTERSTORE dest-key key-name [key-name …]—将那些同时存在于所有集合的元素(数学上的交集运算)存储到 dest-key 键里面

SUNION

SUNION key-name [key-name …]—返回那些至少存在于一个集合中的元素(数学上的并集计算)

SUNIONSTORE

SUNIONSTORE dest-key key-name [key-name …]—将那些至少存在于一个集合中的元素(数学上的并集计算)存储到 dest-key 键里面

Redis Desktop Manager 汉化教程 redis in action中文版_字符串_05

Redis Desktop Manager 汉化教程 redis in action中文版_偏移量_06

hash散列常用命令

命令

行为

HSET

在散列里面关联起给定的键值对

HGET

获取指定散列键的值

HGETALL

获取散列包含的所有键值对

HDEL

HDEL key-name key [key …]—删除散列里面的一个或多个键值对,返回成功找到并删除的键值对数量

HLEN

HLEN key-name—返回散列包含的键值对数量

HMGET

HMGET key-name key [key …]—从散列里面获取一个或多个键的值

HMSET

HMSET key-name key value [key value …]—为散列里面的一个或多个键设置值

HEXISTS

HEXISTS key-name key—检查给定键是否存在于散列中

HKEYS

HKEYS key-name—获取散列包含的所有键

HVALS

HVALS key-name—获取散列包含的所有值

HGETALL

HGETALL key-name—获取散列包含的所有键值对

HINCRBY

HINCRBY key-name increment—将键key存储的值加上整数increment

HINCRBYFLOAT

HINCRBYFLOAT key-name key increment—将键key存储的值加上浮点数increment

尽管有 HGETALL 存在,但 HKEYS 和 HVALS 也是非常有用的:如果散列包含的值非常大,那么用户可以先使用 HKEYS 取出散列包含的所有键,然后再使用 HGET 一个接一个地取出键的值,从而避免因为一次获取多个大体积的值而导致服务器阻塞。

Redis Desktop Manager 汉化教程 redis in action中文版_redis_07

Redis Desktop Manager 汉化教程 redis in action中文版_有序集合_08

zset有序集合常用命令

命令

行为

ZADD

ZADD key-name score member [score member …]—将带有给定分值的成员添加到有序

ZRANGE

ZRANGE key-name start stop [WITHSCORES]—返回有序集合中排名介于 start 和 stop之间的成员,如果给定了可选的 WITHSCORES 选项,那么命令会将成员的分值也一并返回

ZRANGEBYSCORE

获取有序集合在给定分值范围内的所有元素

ZREM

ZREM key-name member [member …]—从有序集合里面移除给定的成员,并返回被移除成员的数量

ZCARD

ZCARD key-name—返回有序集合包含的成员数量

ZINCRBY

ZINCRBY key-name increment member—将 member 成员的分值加上 increment

ZCOUNT

ZCOUNT key-name min max—返回分值介于 min 和 max 之间的成员数量

ZRANK

ZRANK key-name member—返回成员 member 在有序集合中的排名

ZSCORE

ZSCORE key-name member—返回成员 member 的分值

ZREVRANK

ZREVRANK key-name member—返回有序集合里成员 member 的排名,成员按照分值从大到小排列

ZREVRANGE

ZREVRANGE key-name start stop [WITHSCORES]—返回有序集合给定排名范围内的成员,成员按照分值从大到小排列

ZRANGEBYSCORE

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]—返回有序集合中,分值介于 min 和 max 之间的所有成员

ZREVRANGEBYSCORE

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]—获取有序集合中分值介于 min 和 max 之间的所有成员,并按照分值从大到小的顺序来返回它们

ZREMRANGEBYRANK

ZREMRANGEBYRANK key-name start stop—移除有序集合中排名介于start和stop之间的所有成员

ZREMRANGEBYSCORE

ZREMRANGEBYSCORE key-name min max—移除有序集合中分值介于 min 和 max 之间的所有成员

ZINTERSTORE

ZINTERSTORE dest-key key-count key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]—对给定的有序集合执行类似于集合的交集运算

ZUNIONSTORE

ZUNIONSTORE dest-key key-count key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]—对给定的有序集合执行类似于集合的并集运算

Redis Desktop Manager 汉化教程 redis in action中文版_字符串_09

Redis Desktop Manager 汉化教程 redis in action中文版_redis_10

Chapter01.java

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ZParams;

import java.util.*;

/**
 * @author DZHooo
 * @version 1.0
 * @date 2021/11/21 22:53
 * @description: TODO
 */

public class Chapter01 {

    /**
     * 一个有序集合 key:文章ID , value:文章发布时间
     * 一个有序集合 key:文章ID , value:文章的评分
     * 集合 key:文章ID , value:已投票用户ID
     * 散列 key:文章ID , value: (title: value, link: value,...)
     *
     */

    private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;   //七天的秒数

    private  static final int VOTE_SCORE = 432;    //   86400 / 200 = 432 书中200票的原因

    private static final int ARTICLES_PER_PAGE = 25;

    public static void main(String[] args) {
        new Chapter01().run();
    }

    public void run() {
        Jedis conn = new Jedis("localhost");
        conn.select(15);

        String articleId = postArticle(
                conn, "username", "A title", "http://www.google.com");
        System.out.println("We posted a new article with id: " + articleId);
        System.out.println("Its HASH looks like:");
        Map<String,String> articleData = conn.hgetAll("article:" + articleId);
        for (Map.Entry<String,String> entry : articleData.entrySet()){
            System.out.println("  " + entry.getKey() + ": " + entry.getValue());
        }

        System.out.println();

        articleVote(conn, "other_user", "article:" + articleId);
        String votes = conn.hget("article:" + articleId, "votes");
        System.out.println("We voted for the article, it now has votes: " + votes);
        assert Integer.parseInt(votes) > 1;

        System.out.println("The currently highest-scoring articles are:");
        List<Map<String,String>> articles = getArticles(conn, 1);
        printArticles(articles);
        assert articles.size() >= 1;

        addGroups(conn, articleId, new String[]{"new-group"});
        System.out.println("We added the article to a new group, other articles include:");
        articles = getGroupArticles(conn, "new-group", 1);
        printArticles(articles);
        assert articles.size() >= 1;
    }

    //调用这个函数进行投票,投票限制日期,只能投一次
    public void articleVote(Jedis conn,String user,String article) {
        //用UTC时区1970年1月1日到现在为止经过的秒数 减去 七天的秒数
        long cutoff = (System.currentTimeMillis() / 1000) - ONE_WEEK_IN_SECONDS;
        //这个有序集合的成员为文章ID,分值为文章的发布时间  获取这个文章发布的时间秒数 如果大于cutoff,说明文章发布超过七天
        if(conn.zscore("time:",article) < cutoff) {
            return;
        }
        //获取字符串article中的文章ID,在':'之后
        String articleId = article.substring(article.indexOf(':') + 1);
        //投票在集合中报存,键名为voted:[文章ID],值为用户名,用集合存可以让一个用户只能投同一个文章一次票
        if(conn.sadd("voted:" + articleId, user) == 1) {
            //在第二个有序集合中,分值为文章的评分,投一票让该文章评分自增
            conn.zincrby("score:",VOTE_SCORE,article);
            //投票数量自增   散列用来存文章内容,键名为文章ID,值为文章内容对应的键值
            conn.hincrBy(article,"votes",1);
        }
    }

    //发布文章
    public String postArticle(Jedis conn, String user, String title, String link) {
        //文章ID自增+1
        String articleId = String.valueOf(conn.incr("article:"));

        String voted = "voted:" + articleId;
        //为这篇文章新增一个键名为voted:文章ID的集合,先为集合加一个成员user
        conn.sadd(voted, user);
        //设置过期时间七天
        conn.expire(voted, ONE_WEEK_IN_SECONDS);

        long now = System.currentTimeMillis() / 1000;
        //文章ID
        String article = "article:" + articleId;
        //散列的值
        HashMap<String,String> articleData = new HashMap<>();
        articleData.put("title", title);
        articleData.put("link", link);
        articleData.put("user", user);
        articleData.put("now", String.valueOf(now));
        articleData.put("votes", "1");
        //文章数据 键为文章ID,值为文章数据
        conn.hmset(article,articleData);
        //评分有序集合
        conn.zadd("score:",now + VOTE_SCORE,article);
        //时间有序集合
        conn.zadd("time:",now,article);

        return articleId;
    }

    //这个只用与提取评分的有序集合
    public List<Map<String, String>> getArticles(Jedis conn, int page) {
        return getArticles(conn,page,"score:");
    }

    //这个可以通过order取发布时间或评分的有序集合  参数order也是有序集合的键名
    public List<Map<String, String>> getArticles(Jedis conn, int page, String order) {

        int start = (page - 1) * ARTICLES_PER_PAGE;
        int end = start + ARTICLES_PER_PAGE - 1;

        Set<String> ids = conn.zrevrange(order, start, end);
        List<Map<String,String>> articles = new ArrayList<>();
        for(String id : ids) {
            Map<String,String> articleData = conn.hgetAll(id);
            articleData.put("id", id);
            articles.add(articleData);
        }

        return articles;
    }


    public void addGroups(Jedis conn, String articleId, String[] toAdd) {
        String article = "article:" + articleId;
        for(String group : toAdd) {
            conn.sadd("group:" + group, article);
        }
    }


    //程序可以得到按照文章评分排序的群组文章
    public List<Map<String,String>> getGroupArticles(Jedis conn, String group, int page) {
        return getGroupArticles(conn, group, page,"score:");
    }


    public List<Map<String,String>> getGroupArticles(Jedis conn, String group, int page, String order) {
        String key = order + group;
        if(!conn.exists(key)) {
            ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX);
            conn.zinterstore(key, params, "group:" + group, order);
            conn.expire(key, 60);
        }
        return getArticles(conn, page, key);
    }

    private void printArticles(List<Map<String,String>> articles){
        for (Map<String,String> article : articles){
            System.out.println("  id: " + article.get("id"));
            for (Map.Entry<String,String> entry : article.entrySet()){
                if (entry.getKey().equals("id")){
                    continue;
                }
                System.out.println("    " + entry.getKey() + ": " + entry.getValue());
            }
        }
    }

}