Redis入门指南(五):从零到分布式缓存-其他类型及Java客户端操作redis

文章目录

  • [一. stream](#一. stream)
  • [二. geospatial](#二. geospatial)
  • [三. HyperLogLog](#三. HyperLogLog)
  • [四. bitmaps](#四. bitmaps)
  • [五. bitfield](#五. bitfield)
  • [六. 渐进式遍历](#六. 渐进式遍历)
  • [七. 数据库管理简单命令](#七. 数据库管理简单命令)
    • [1. select](#1. select)
    • [2. dbsize](#2. dbsize)
    • [3. flushdb和flushall](#3. flushdb和flushall)
  • [八. RESP](#八. RESP)
  • [九. Java客户端操作Redis](#九. Java客户端操作Redis)
    • [1. 连接Redis](#1. 连接Redis)
      • (1)创建redis容器
      • [(2) Java客户端连接Redis](#(2) Java客户端连接Redis)
      • [(3) 测试连接](#(3) 测试连接)
    • [2. get和set](#2. get和set)
    • [3. exists和del](#3. exists和del)
    • [4. keys](#4. keys)
    • [5. expire, ttl, type](#5. expire, ttl, type)
    • [6. mset和mget](#6. mset和mget)
    • [7. getrange和setrange](#7. getrange和setrange)
    • [8. append, incr, decr](#8. append, incr, decr)
    • [9. lpush, rpush, lrange](#9. lpush, rpush, lrange)
    • [10. lpop和rpop](#10. lpop和rpop)
    • [11. blpop和llen](#11. blpop和llen)
    • [12. sadd, smembers, sismember, scard, spop](#12. sadd, smembers, sismember, scard, spop)
    • [13. sinter和sinterStore](#13. sinter和sinterStore)
    • [14. hset, hget, hexists, hdel](#14. hset, hget, hexists, hdel)
    • [15. hkeys, hvals, hmset, hmget](#15. hkeys, hvals, hmset, hmget)
    • [16. zadd和zrange](#16. zadd和zrange)
    • [17. zcard, zrem, zscore, zrank](#17. zcard, zrem, zscore, zrank)

一. stream

Stream相当于一个阻塞队列, 可以模拟实现事件传播机制, 添加进新元素就唤醒消费者进行消费, 主要作为消息队列使用, 比list中的blpop/brpop功能更强大

二. geospatial

Redis地理空间索引允许存储坐标并搜索它们。此数据结构可用于查找给定半径或边界框内的附近点, 存储经纬度信息, 常用于地图功能的开发

三. HyperLogLog

HyperLogLog 主要用于计算集合中元素基数, 应用场景是统计一个软件的用户访问量(UV), set中也有该功能, 但是因为set中存储的是集合的详细信息, 因此当UV过大时会十分占用内存空间, 而相比于HyperLogLog的统计, 该类型只保存元素的特征, 不保存详细信息, 因此可以用最多12kb的内存空间完成统计, 可以说这种设计思想十分香, 当然节省空间的背后, 是精确度为, HyperLogLog的误差范围在0.81%左右

四. bitmaps

位图这种数据结果相信大家应该不陌生, 只存储整数, 用整数来表示状态, 存储一个整数时, 需要建立一个大于等于最大元素长度的位图, 从右往左数只修改对应下标的比特位为1, 优点是既节省空间查询效率又高, 但是局限性也很大

五. bitfield

位域, 与C语言中的位段比较相似, 看官方文档:Redis位字段允许您设置、递增和获取任意位长的整数值。例如,您可以对从无符号1位整数到有符号63位整数的任何值进行操作。
这些值是使用二进制编码的Redis字符串存储的。位字段支持原子读、写和增量操作,使其成为管理计数器和类似数值的良好选择

六. 渐进式遍历

bash 复制代码
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

下面我们一一介绍每个参数的含义👇
1. 如果我们想要知道在服务器中有哪些key, 前面我们学过(keys * )命令, 同时我们也知道这个命令十分危险, 可能会造成Redis服务器阻塞, 但如果我们真的需要获取一些key, 又不想太影响性能, 这时渐进式遍历使我们最好的选择

2. 看上面图片我们可能有疑惑, 为什么第二次渐进式遍历完后, 光标执行了 "7" 的位置, 不应该指向 "5" 吗?

其实光标不等于下标, 除了刚开始特殊的 "0" 光标代表从头开始遍历外, 其他的光标都是一个字符串, 而不是一个整数, 而这个光标的概念只要Redis服务器理解, 可以解析知道指定哪个元素, 但是我们程序员和Redis客户端是不能理解的, 当光标再次回到 "0" 的时候说明遍历已经结束


3. MATCH pattern 即匹配规则, 我们在介绍keys 的时候着重介绍过匹配规则, 这里不过多赘述
4. COUNT count 建议获取的key的个数, 不指定的默认是10, 获取到的key的个数与指定的count个数相近, 不一定一致, 不是很精确
TYPE type 代表value的类型, 我们知道key只有string类型, 但是value确实有多种类型, 这里我们指定只获取对应value类型的key


5. scan命令之所以可以更安全的遍历所有的key, 是因为每次遍历都不会在Redis服务器保存状态信息, 而是通过光标直接定位到对应位置的元素


6. 渐进式遍历过程中, 如果出现键的修改/删除/增加, 可能就会导致重复/遗漏键

七. 数据库管理简单命令

1. select

bash 复制代码
select index

在之前我们很多人都学过MySQL, MySQL中会包含多个库, 库中又会包含多个表, 那么在Redis中会不会有数据库的概念你?

在Redis中也有数据库, 但是我们不能主动创建/删除数据库, 只要固定的16个数据库, 而我们默认使用的就是0号数据库, 同时每个数据库之间是隔离的


2. dbsize

bash 复制代码
dbsize

获取当前数据库中key的总个数, 时间复杂度O(1)

3. flushdb和flushall

1. flushdb 用于删除当前数据库中的所有key
2. flushall 用于删除所有数据库中的所有key, 一节更比一节强, 一个比一个更危险

八. RESP

在工作中, 我们不会对着Redis命名行客户端直接进行操作, 而是通过通过自定义客户端来对Redis服务器进行操作, 又因为Redis的服务器和客户端通过自定义的应用层协议进行通信, 因此我们想要定制化一个客户端就需要知道客户端的自定义协议, 幸运的该协议是Redis官方早已公开(RESP)


1. (用\r\n将协议的每部分分割, 保证每个命令不冲突)

2. RESP序列化有效载荷中的第一个字节始终标识其类型。后续字节构成该类型的内容

3. 简单类型类似于表示纯文字值的编程语言中的标量。布尔值和整数就是这样的例子
4. 下面是不同类型对应的符号👇

九. Java客户端操作Redis

1. 连接Redis

(1)创建redis容器

我们这里使用docker来连接Redis, 首先拉取镜像, 然后创建容器的同时设置密码, 这里直接映射的是本地6379端口

bash 复制代码
# 拉取镜像, 默认拉取的是最新版本
docker pull redis
# 创建容器, 同时指定密码
docker run --name oj-redis -d -p 6379:6379 redis --requirepass "580231"

(2) Java客户端连接Redis

操作Redis的库有很多, 这里我们选择jedis, 首先引入jedis依赖

java 复制代码
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>6.2.0</version>
        </dependency>

通过连接池来节省开销

java 复制代码
JedisPool jedisPool = new JedisPool("127.0.0.1",6379,"default","580231");

(3) 测试连接

bash 复制代码
    public static void main(String[] args) {
        JedisPool jedisPool = new JedisPool("127.0.0.1",6379,"default","580231");
        try(Jedis jedis = jedisPool.getResource()){
            String ping = jedis.ping();
            System.out.println(ping);
        }
    }

2. get和set

可以说和Redis原生客户端命令基本一样, 这里简单演示下

java 复制代码
    static void t1(Jedis jedis) {
        jedis.set("k1","999");
        String v1 = jedis.get("k1");
        long t1 = jedis.ttl("k1");
        System.out.println("v1: " + v1);
        System.out.println("k1的超时时间: " + t1 + "s");
        System.out.println("--------");
        jedis.setex("k2",5,"888");
        long t2 = jedis.ttl("k2");
        String v2 = jedis.get("k2");
        System.out.println("v2: " + v2);
        System.out.println("k2的超时时间: " + t2 + "s");
    }

3. exists和del

需要注意: 当exists方法传入单个参数的时候, 返回值为boolean类型, 表示是否存活, 当传入参数个数为多个时, 返回值类型为long类型, 表示存活键的个数, 同样del也可以同时删除多个key

java 复制代码
    static void t1(Jedis jedis) {
        jedis.flushAll();
        jedis.set("k1","111");
        jedis.set("k2","222");
        boolean e1 = jedis.exists("k1");
        long el1 = jedis.exists("k1", "k2");
        System.out.println("k1: " + e1);
        System.out.println("存在个数: " + el1);
        System.out.println("--------");
        jedis.del("k1");
        boolean e2 = jedis.exists("k1");
        long el2 = jedis.exists("k1", "k2");
        System.out.println("删除k1后: " + e2);
        System.out.println("存在个数: " + el2);
    }

4. keys

keys方法的参数传入的是匹配规则

java 复制代码
    static void t2(Jedis jedis) {
        jedis.flushAll();
        jedis.set("k1","111");
        jedis.set("k2","222");
        jedis.set("k3","333");
        Set<String> keys = jedis.keys("*");
        System.out.println(keys);
    }

5. expire, ttl, type

java 复制代码
    static void t3(Jedis jedis) {
        jedis.flushAll();
        jedis.set("k1","111");
        jedis.expire("k1",7);
        long t = jedis.ttl("k1");
        System.out.println("过期时间: " + t + "s");

        String type = jedis.type("k1");
        System.out.println("k1- > type: " + type);

        jedis.rpush("k2","1","2","3");
        type = jedis.type("k2");
        System.out.println("k2- > type: " + type);

        jedis.sadd("k3","1","2","3");
        type = jedis.type("k3");
        System.out.println("k3- > type: " + type);

        jedis.zadd("k4",20,"1");
        type = jedis.type("k4");
        System.out.println("k4- > type: " + type);


        jedis.hset("k5","f","v");
        type = jedis.type("k5");
        System.out.println("k5- > type: " + type);

    }

6. mset和mget

java 复制代码
    static void t4(Jedis jedis) {
        jedis.flushAll();
        jedis.mset("k1","1","k2","2","k3","3");
        List<String> values = jedis.mget("k1", "k2", "k3", "k4");
        System.out.println("values: " + values);
    }

一个key对应一个value, 当key不存在时, 对应的值为null

7. getrange和setrange

java 复制代码
    static void t5(Jedis jedis) {
        jedis.flushAll();
        jedis.set("k","123456789");
        String val = jedis.getrange("k", 2, 5);
        System.out.println("value: " + val);
        System.out.println("------------");
        jedis.setrange("k",2,"xyz");
        val = jedis.get("k");
        System.out.println("value: " + val);
    }

8. append, incr, decr

java 复制代码
    static void t6(Jedis jedis) {
        jedis.flushAll();
        jedis.set("k","123");
        jedis.append("k", "xyz");
        String ret = jedis.get("k");
        System.out.println(ret);
        System.out.println("------------");
        jedis.set("k2","100");
        jedis.incr("k2");
        ret = jedis.get("k2");
        System.out.println(ret);
        System.out.println("------------");
        jedis.set("k3","100");
        jedis.decr("k3");
        ret = jedis.get("k3");
        System.out.println(ret);
    }

9. lpush, rpush, lrange

java 复制代码
    static void t7(Jedis jedis) {
        jedis.flushAll();
        jedis.lpush("k1","11","22","33");
        List<String> ret = jedis.lrange("k1", 0, -1);
        System.out.println(ret);
        System.out.println("------------");
        jedis.rpush("k2","11","22","33");
        ret = jedis.lrange("k2", 0, -1);
        System.out.println(ret);
    }

10. lpop和rpop

java 复制代码
    static void t8(Jedis jedis) {
        jedis.flushAll();
        jedis.lpush("k1","11","22","33");
        List<String> ret = jedis.lpop("k1", 3);
        System.out.println(ret);
        System.out.println("------------");
        jedis.lpush("k2","11","22","33");
        ret = jedis.rpop("k2", 3);
        System.out.println(ret);
    }

11. blpop和llen

java 复制代码
    static void t9(Jedis jedis) {
        jedis.flushAll();
        jedis.lpush("k1","11","22","33");
        long len = jedis.llen("k1");
        System.out.println("pop前长度: " + len);
        List<String> ret = jedis.blpop(3,"k1");
        System.out.println(ret);
        System.out.println("------------");
        len = jedis.llen("k1");
        System.out.println("pop后长度: " + len);
    }

要注意的是blpop 返回值是一个二元素, 从哪个key中删除及删除的元素

12. sadd, smembers, sismember, scard, spop

java 复制代码
    static void t10(Jedis jedis) {
        jedis.flushAll();
        jedis.sadd("k","11","22","33");
        Set<String> values = jedis.smembers("k");
        System.out.println("values: " + values);
        System.out.println("------------");
        boolean b = jedis.sismember("k", "11");
        System.out.println("k是否存在元素11: " + b);
        System.out.println("------------");
        long len = jedis.scard("k");
        System.out.println("集合的元素个数: " + len);
        System.out.println("------------");
        String ret = jedis.spop("k");
        System.out.println("弹出的元素为: " + ret);
    }

13. sinter和sinterStore

前面我们已经讲过, 这两个都是求交集, 区别是sinterStore是将交集的结果存到一个新的集合中

java 复制代码
    static void t11(Jedis jedis) {
        jedis.flushAll();
        jedis.sadd("k1","11","22","33");
        jedis.sadd("k2","22","33","44");
        Set<String> sinter = jedis.sinter("k1", "k2");
        System.out.println("sinter: " + sinter);
        System.out.println("------------");
        long len = jedis.sinterstore("k3", "k1", "k2");
        System.out.println("交集的元素个数: " + len);
        Set<String> sinterStore = jedis.smembers("k3");
        System.out.println("sinterStore: " + sinterStore);
    }

14. hset, hget, hexists, hdel

java 复制代码
    static void t12(Jedis jedis) {
        jedis.flushAll();
        Map<String,String> map = new HashMap<>();
        map.put("f1","1");
        map.put("f2","2");
        map.put("f3","3");
        jedis.hset("k",map);
        String hget = jedis.hget("k", "f1");
        System.out.println("hget: " + hget);
        System.out.println("------------");
        boolean hexists1 = jedis.hexists("k", "f1");
        boolean hexists2 = jedis.hexists("k", "f4");
        System.out.println("hexists1: " + hexists1);
        System.out.println("hexists2: " + hexists2);
        System.out.println("------------");
        long hdel = jedis.hdel("k", "f1", "f2");
        System.out.println("删除的键值对个数hdel: " + hdel);
    }

15. hkeys, hvals, hmset, hmget

注意hvals中元素是无序的, 不一定是从f1开始一一对应到最后

java 复制代码
    static void t12(Jedis jedis) {
        jedis.flushAll();
        Map<String,String> map = new HashMap<>();
        map.put("f1","b12");
        map.put("f2","a22");
        map.put("f3","c23");
        jedis.hmset("k",map);
        Set<String> hkeys = jedis.hkeys("k");
        List<String> hvals = jedis.hvals("k");
        System.out.println("hkeys: " + hkeys);
        System.out.println("hvals: " + hvals);
        System.out.println("------------");
        List<String> hmget = jedis.hmget("k", "f1", "f2", "f3");
        System.out.println("hmget: " + hmget);
    }

16. zadd和zrange

java 复制代码
    static void t13(Jedis jedis) {
        jedis.flushAll();
        jedis.zadd("k",10,"张三");
        Map<String,Double> map = new HashMap<>();;
        map.put("李四",20.0);
        map.put("王五",15.0);
        jedis.zadd("k",map);
        List<String> members = jedis.zrange("k", 0, -1);
        System.out.println(members);
        System.out.println("------------");
        List<Tuple> zrangeWzithScores = jedis.zrangeWithScores("k", 0, -1);
        System.out.println(zrangeWzithScores);
    }

17. zcard, zrem, zscore, zrank

java 复制代码
    static void t14(Jedis jedis) {
        jedis.flushAll();
        jedis.zadd("k",10,"张三");
        Map<String,Double> map = new HashMap<>();;
        map.put("李四",20.0);
        map.put("王五",15.0);
        jedis.zadd("k",map);
        long len = jedis.zcard("k");
        System.out.println("元素个数: " + len);
        System.out.println("------------");
        Double zscore = jedis.zscore("k", "王五");
        System.out.println("zscore: " + zscore);
        System.out.println("------------");
        Long zrank = jedis.zrank("k", "王五");
        System.out.println("zrank: " + zrank);
        System.out.println("------------");
        long zrem = jedis.zrem("k", "王五");
        System.out.println("删除的元素个数: " + zrem);
        List<Tuple> zrangeWithScores = jedis.zrangeWithScores("k", 0, -1);
        System.out.println("删除王五后的zrangeWithScores: " + zrangeWithScores);
    }
相关推荐
@淡 定4 小时前
Redis热点Key独立集群实现方案
数据库·redis·缓存
野生的码农4 小时前
码农的妇产科实习记录
android·java·人工智能
吳所畏惧4 小时前
Linux环境/麒麟V10SP3下离线安装Redis、修改默认密码并设置Redis开机自启动
linux·运维·服务器·redis·中间件·架构·ssh
毕设源码-赖学姐5 小时前
【开题答辩全过程】以 高校人才培养方案管理系统的设计与实现为例,包含答辩的问题和答案
java
一起努力啊~5 小时前
算法刷题-二分查找
java·数据结构·算法
小途软件5 小时前
高校宿舍访客预约管理平台开发
java·人工智能·pytorch·python·深度学习·语言模型
J_liaty5 小时前
Java版本演进:从JDK 8到JDK 21的特性革命与对比分析
java·开发语言·jdk
+VX:Fegn08956 小时前
计算机毕业设计|基于springboot + vue律师咨询系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
daidaidaiyu6 小时前
一文学习和实践 当下互联网安全的基石 - TLS 和 SSL
java·netty
hssfscv6 小时前
Javaweb学习笔记——后端实战2_部门管理
java·笔记·学习