【redis初阶】redis客户端

目录

一、基本介绍

二、认识RESP(redis自定的应用层协议名称)

三、访问github的技巧

四、安装redisplusplus

4.1 安装 hiredis**

4.2 下载 redis-plus-plus 源码

4.3 编译/安装 redis-plus-plus

五、编写运行helloworld

六、redis命令演示

6.1 通用命令的使用

6.2 string的使用

6.3 list的使用

6.4 set的使用

6.5 hash的使用

6.6 zset的使用


redis学习🥳

一、基本介绍

在前面的学习中主要是学习 redis 的各种基本操作/命令,都是在 redis 命令行客户端中手动执行 redis各种命令,但这种操作方式不是我们日常开发中的主要形式;更多的时候,我们是使用 redis 的 api 来实现定制化的 redis 客户端程序,进一步操作 redis 服务器;

不管是 redis 提供的命令行客户端,还是第三方的图形化客户端,他们本质上都属于是“通用的客户端程序”。但相比之下,我们在工作中更希望使用到的是“专用的”“定制化”的客户端程序;

二、认识RESP(redis自定的应用层协议名称)

我们为什么能编写出一个自定义的redis客户端呢?

我们知道在网络通信过程中,会使用到很多的“协议”

应用层往下的协议是固定好的,是在系统内核或者驱动程序中实现的,我们是不可修改的,但是对于应用层来说,虽然业界有很多成熟的应用层协议,比如 http 等,但是此处更多的时候,都会“自定义”应用层协议,redis 此处应用层协议,就是自定义的应用层协议,客户端按照 resp 协议发送请求,服务器按照这个协议进行解析,在按照这个协议构造响应,客户端在解析这个响应,完成客户端和服务器的通信;

因此:resp 就是 redis 自定义的客户端和服务器用于通信的应用层协议;

resp协议特点:

  • 简单好实现;
  • 快速进行解析;
  • 肉眼可读;
  • 基于传输层的tcp,但是与tcp又没有强耦合;
  • 请求和响应之间的通信是一问一答的形式(客户端给服务器发起一个请求,服务器返回一个响应);
  • 客户端给redis服务器发送命令时:是以bulk string数组的形式发送的redis命令,对于不同的redis命令,服务器返回的结果是不一样的(ok、整个数组...);

在RESP中,第一个字节决定了数据类型:

  • 对于Simple Strings,回复的第一个字节是“+” eg:"+OK\r\n"
  • 对于Errors,回复的第一个字节是“-”   eg:"-Error message\r\n"
  • 对于Integers,回复的第一个字节是“:”   eg:":1000\r\n"
  • 对于Bulk Strings,回复的第一个字节是“$”   eg:"$5\r\nhello\r\n"
  • 对于Arrays,回复的第一个字节是“*”   eg:"*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n"

在进行通信的时候,服务器就把构造好的字符串,写入到 tcp socket 中;

Simple Strings 和 Bulk Strings 的区别:Simple String 只能用来传输文本,Bulk String 可以传输二进制数据;

上述这套协议公开已久,已经有很多大佬,实现了这套协议的解析/构造,在写代码的时候,我们不需要按照上述的协议,解析/构造字符串,只要使用这些大佬们提供的库,就可以比较简单方便的来完成和 redis 服务器通信的操作了;

三、访问github的技巧

翻墙 or 下载游戏加速器,推荐:watt toolkit

选中gitup,一键加速

四、安装redisplusplus

C++ 操作 redis 的库有很多,咱们此处使用 redis-plus-plus.

这个库的功能强大,使用简单.

Github 地址:  https://github.com/sewenew/redis-plus-plus

4.1 安装 hiredis**

redis-plus-plus 是基于 hiredis 实现的.

hiredis 是一个 C 语言实现的 redis 客户端.

因此需要先安装 hiredis. 直接使用包管理器安装即可.

在 Ubuntu 镜像下:

apt install libhiredis-dev

4.2 下载 redis-plus-plus 源码

git clone https://github.com/sewenew/redis-plus-plus.git

4.3 编译/安装 redis-plus-plus

redis-plus-plus 是使用 cmake 构建工具进行构建的,cmake 相当于是 Makefile 的升级版,Makefile 本身功能比较简陋,比较原始,写起来也比较麻烦实际开发中很少会手写 makefile,cmake 就是通过程序来生成 makefile 的 工具;

在 Ubuntu 镜像下:

使用 cmake 构建:

cd redis-plus-plus# 创建一个 build 目录是习惯做法,并非必须。目的是为了让编译生成的临时文件都放到 build 下,避免污染源代码目录
mkdir build
cd build# 这个操作是生成makefile,此处..指向的是刚才 CMakeLits.txt 文件所在的目录
cmake3 ..make    # 进行编译
sudo make install # 将编译生成的 .a .so 等系列库拷贝到系统目录

make 后结果:

make install 后结果:

构建成功后,会在 /usr/local/include/ 中多出 sw 目录,并且内部包含 redis-plus-plus 的一系列头文件;

会在 /usr/local/lib/ 中多出一系列 libredis 库文件.

五、编写运行helloworld

创建代码目录:

编写 hello.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <sw/redis++/redis++.h>using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;int main() {// 创建 Redis 对象的时候,需要在构造函数中指定 redis 服务器地址和端口;sw::redis::Redis redis("tcp://127.0.0.1:6379");// 使用 ping 方法,让客户端给服务器发送了一个 PING,然后服务器就会返回一个 PONG,通过返回值获取的string result = redis.ping();cout << result << endl;
}

编写 makefile 文件:

hello:hello.cppg++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread# /usr/local/lib/libredis++.a               redis自己的静态库# /usr/lib/x86_64-linux-gnu/libhiredis.a    hiredis的静态库# -pthread                                    线程库.PHONY:clean
clean:rm hello

编译运行:

六、redis命令演示

工具文件:

util.hpp 文件:

# pragma once# include <iostream>
# include <vector>
#include <string>// 打印容器内元素
template<typename T>
inline void printContainer(const T& container) {for(const auto& elem : container) {std::cout << elem << std::endl;}
}// 当容器内元素是 pair 类型时,打印容器内元素
template<typename T>
inline void printContainerPair(const T& container) {for(const auto& elem : container) {std::cout << elem.first << " : " << elem.second << std::endl;}
}// 当容器内元素是 optional 类型时,打印容器内元素
template<typename T>
inline void printContainerOptional(const T& container) {for(const auto& elem : container) {if(elem) {std::cout << elem.value() << std::endl;} else {std::cout << "元素无效" << std::endl;}}
}

6.1 通用命令的使用

genetric.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <chrono>
#include <thread>
#include <sw/redis++/redis++.h>#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;
using sw::redis::Redis;// get 和 set 的使用
void test1(Redis& redis) {cout << "get 和 set 的使用" << endl;// 清空数据库,避免之前残留的数据有干扰redis.flushall();// 使用 set 设置 keyredis.set("key1", "111");redis.set("key2", "222");redis.set("key3", "333");// 使用 get 获取到 key 对应的 valueauto value1 = redis.get("key1");if(value1) {cout << "value1 = " << value1.value() << endl;} else {cout << "当前 key 不存在" << endl;}auto value2 = redis.get("key2");if(value2) {cout << "value2 = " << value2.value() << endl;} else {cout << "当前 key 不存在" << endl;}auto value3 = redis.get("key3");if(value3) {cout << "value3 = " << value3.value() << endl;} else {cout << "当前 key 不存在" << endl;}auto value4 = redis.get("key4");if(value4) {cout << "value4 = " << value4.value() << endl;} else {cout << "当前 key 不存在" << endl;}
}// exists 的使用
void test2(Redis& redis) {cout << "exists" << endl;redis.flushall();redis.set("key", "111");redis.set("key3", "111");auto ret = redis.exists("key");cout << ret << endl;ret = redis.exists("key2");cout << ret << endl;ret = redis.exists({"key1", "key2", "key3"});cout << ret << endl;
}// del 的使用
void test3(Redis& redis) {cout << "del" << endl;redis.flushall();redis.set("key1", "111");redis.set("key2", "222");vector<string> input{"key1", "key2", "key3"};auto ret = redis.del(input.begin(), input.end());cout << ret << endl;ret = redis.exists({"key1", "key2"});cout << ret << endl;
}// keys 的使用
void test4(Redis& redis) {cout << "keys" << endl;redis.flushall();redis.set("key1", "111");redis.set("key2", "222");redis.set("key3", "333");redis.set("key4", "444");redis.set("key5", "555");redis.set("key6", "666");// keys 的第二个参数是一个“插入迭代器”,咱们需要先准备好一个保存结果的容器// 接下来再创建一个插入迭代器指向容器的位置. 就可以把 keys 获取到的结果依次通过刚才的插入迭代器插入到容器的指定位置中了.vector<string> result;auto it = std::back_inserter(result);redis.keys("*", it);printContainer(result);
}void test5(Redis& redis) {using namespace std::chrono_literals;std::cout << "expire and ttl" << std::endl;redis.flushall();redis.set("key", "111");// 10s => std::chrono::seconds(10)redis.expire("key", 10s);std::this_thread::sleep_for(3s);auto time = redis.ttl("key");std::cout << time << std::endl;
}void test6(sw::redis::Redis& redis) {std::cout << "type" << std::endl;redis.flushall();redis.set("key", "111");string result = redis.type("key");std::cout << "key: " << result << std::endl;redis.lpush("key2", "111");result = redis.type("key2");std::cout << "key2: " << result << std::endl;redis.hset("key3", "aaa", "111");result = redis.type("key3");std::cout << "key3: " << result << std::endl;redis.sadd("key4", "aaa");result = redis.type("key4");std::cout << "key4: " << result << std::endl;redis.zadd("key5", "吕布", 99);result = redis.type("key5");std::cout << "key5: " << result << std::endl;
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);// test5(redis);test6(redis);
}

get 和 set:test1()结果:

exists:test2()结果:

del:test3()结果:

keys:test4()结果:

expire and ttl:test5()结果:

type:test6()结果:

6.2 string的使用

string.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <chrono>
#include <thread>#include <sw/redis++/redis++.h>
#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;using sw::redis::Redis;using namespace std::chrono_literals;void test1(Redis& redis) {std::cout << "get 和 set" << std::endl;redis.flushall();redis.set("key", "111");auto value = redis.get("key");if (value) {std::cout << "value: " << value.value() << std::endl;}redis.set("key", "222");value = redis.get("key");if (value) {std::cout << "value: " << value.value() << std::endl;}
}void test2(Redis& redis) {std::cout << "set 带有超时时间" << std::endl;redis.flushall();redis.set("key", "111", 10s);std::this_thread::sleep_for(3s);long long time = redis.ttl("key");std::cout << "time: " << time << std::endl;
}void test3(Redis& redis) {std::cout << "set NX 和 XX" << std::endl;redis.flushall();redis.set("key", "111");// set 的重载版本中, 没有单独提供 NX 和 XX 的版本, 必须搭配过期时间的版本来使用. redis.set("key", "222", 0s, sw::redis::UpdateType::EXIST);auto value = redis.get("key");if (value) {std::cout << "value: " << value.value() << std::endl;} else {std::cout << "key 不存在!" << std::endl;}
}void test4(Redis& redis) {std::cout << "mset" << std::endl;redis.flushall();// 第一种写法, 使用初始化列表描述多个键值对// redis.mset({ std::make_pair("key1", "111"), std::make_pair("key2", "222"), std::make_pair("key3", "333") });// 第二种写法, 可以把多个键值对提前组织到容器中. 以迭代器的形式告诉 msetvector<std::pair<string, string>> keys = {{"key1", "111"},{"key2", "222"},{"key3", "333"}};redis.mset(keys.begin(), keys.end());auto value = redis.get("key1");if (value) {std::cout << "value: " << value.value() << std::endl;}value = redis.get("key2");if (value) {std::cout << "value: " << value.value() << std::endl;}value = redis.get("key3");if (value) {std::cout << "value: " << value.value() << std::endl;}
}void test5(Redis& redis) {std::cout << "mget" << std::endl;redis.flushall();vector<std::pair<string, string>> keys = {{"key1", "111"},{"key2", "222"},{"key3", "333"}};redis.mset(keys.begin(), keys.end());vector<sw::redis::OptionalString> result;auto it = std::back_inserter(result);redis.mget({"key1", "key2", "key3", "key4"}, it);printContainerOptional(result);
}void test6(Redis& redis) {std::cout << "getrange 和 setrange" << std::endl;redis.flushall();redis.set("key", "abcdefghijk");string result = redis.getrange("key", 2, 5);std::cout << "result: " << result << std::endl;redis.setrange("key", 2, "xyz");auto value = redis.get("key");std::cout << "value: " << value.value() << std::endl;
}void test7(Redis& redis) {std::cout << "incr 和 decr" << std::endl;redis.flushall();redis.set("key", "100");long long result = redis.incr("key");std::cout << "result: " << result << std::endl;auto value = redis.get("key");std::cout << "value: " << value.value() << std::endl;result = redis.decr("key");std::cout << "result: " << result << std::endl;value = redis.get("key");std::cout << "value: " << value.value() << std::endl;
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);// test5(redis);// test6(redis);test7(redis);return 0;
}

get 和 set:test1()结果:

set 带有超时时间:test2()结果:

set NX 和 XX:test3()结果:

mset 带有超时时间:test4()结果:

mget 带有超时时间:test5()结果:

getrange 和 setrange 带有超时时间:test6()结果:

incr 和 dec 带有超时时间:test7()结果:

6.3 list的使用

list.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <thread>
#include <chrono>
#include <sw/redis++/redis++.h>
#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;
using sw::redis::Redis;using namespace std::chrono_literals;void test1(Redis& redis) {std::cout << "lpush 和 lrange" << std::endl;redis.flushall();// 插入单个元素redis.lpush("key", "111");// 插入一组元素, 基于初始化列表redis.lpush("key", {"222", "333", "444"});// 插入一组元素, 基于迭代器vector<string> values = {"555", "666", "777"};redis.lpush("key", values.begin(), values.end());// lrange 获取到列表中的元素vector<string> results;auto it = std::back_inserter(results);redis.lrange("key", 0, -1, it);printContainer(results);
}void test2(Redis& redis) {std::cout << "rpush" << std::endl;redis.flushall();// 插入单个元素redis.rpush("key", "111");// 插入多个元素, 基于初始化列表redis.rpush("key", {"222", "333", "444"});// 插入多个元素, 基于容器vector<string> values = {"555", "666", "777"};redis.rpush("key", values.begin(), values.end());// 使用 lrange 获取元素vector<string> results;auto it = std::back_inserter(results);redis.lrange("key", 0, -1, it);printContainer(results);
}void test3(Redis& redis) {std::cout << "lpop 和 rpop" << std::endl;redis.flushall();// 构造一个 listredis.rpush("key", {"1", "2", "3", "4"});auto result = redis.lpop("key");if (result) {std::cout << "lpop: " << result.value() << std::endl;}result = redis.rpop("key");if (result) {std::cout << "rpop: " << result.value() << std::endl;}
}void test4(Redis& redis) {using namespace std::chrono_literals;std::cout << "blpop" << std::endl;redis.flushall();auto result = redis.blpop({"key", "key2", "key3"}, 10s);if (result) {std::cout << "key:" << result->first << std::endl;std::cout << "elem:" << result->second << std::endl;} else {std::cout << "result 无效!" << std::endl;}
}void test5(Redis& redis) {std::cout << "llen" << std::endl;redis.flushall();redis.lpush("key", {"111", "222", "333", "444"});long long len = redis.llen("key");std::cout << "len: " << len << std::endl;
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);test5(redis);return 0;
}

lpush 和 lrange:test1()结果:

rpush:test2()结果:

lpop 和 rpo:test3()结果:

blpop:test4()结果:

llen:test5()结果:

6.4 set的使用

set.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <unordered_map>
#include <sw/redis++/redis++.h>#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;
using std::set;using sw::redis::Redis;void test1(Redis& redis) {std::cout << "sadd 和 smembers" << std::endl;redis.flushall();// 一次添加一个元素redis.sadd("key", "111");// 一次添加多个元素(使用初始化列表)redis.sadd("key", {"222", "333", "444"});// 一次添加多个元素(使用迭代器)set<string> elems = {"555", "666", "777"};redis.sadd("key", elems.begin(), elems.end());// 获取到上述元素// 此处用来保存 smembers 的结果, 使用 set 可能更合适. vector<string> result;// auto it = std::back_inserter(result);// 由于此处 set 里的元素顺序是固定的. 指定一个 result.end() 或者 result.begin() 或者其他位置的迭代器, 都无所谓~~auto it = std::inserter(result, result.end());redis.smembers("key", it);printContainer(result);
}void test2(Redis& redis) {std::cout << "sismember" << std::endl;redis.flushall();redis.sadd("key", {"111", "222", "333", "444"});bool result = redis.sismember("key", "555");std::cout << "result: " << result << std::endl;
}void test3(Redis& redis) {std::cout << "scard" << std::endl;redis.flushall();redis.sadd("key", {"111", "222", "333"});long long result = redis.scard("key");std::cout << "result: " << result << std::endl;
}void test4(Redis& redis) {std::cout << "spop" << std::endl;redis.flushall();redis.sadd("key", {"111", "222", "333", "444"});auto result = redis.spop("key");if (result) {std::cout << "result: " << result.value() << std::endl;} else {std::cout << "result 无效!" << std::endl;}
}void test5(Redis& redis) {std::cout << "sinter" << std::endl;redis.flushall();redis.sadd("key1", {"111", "222", "333"});redis.sadd("key2", {"111", "222", "444"});set<string> result;auto it = std::inserter(result, result.end());redis.sinter({"key1", "key2"}, it);printContainer(result);
}void test6(Redis& redis) {std::cout << "sinterstore" << std::endl;redis.flushall();redis.sadd("key1", {"111", "222", "333"});redis.sadd("key2", {"111", "222", "444"});long long len = redis.sinterstore("key3", {"key1", "key2"});std::cout << "len: " << len << std::endl;set<string> result;auto it = std::inserter(result, result.end());redis.smembers("key3", it);printContainer(result);
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);// test5(redis);test6(redis);return 0;
}

sadd 和 smembers:test1()结果:

sismember:test2()结果:

scard:test3()结果:

spop:test4()结果:

sinter:test5()结果:

sinterstore:test6()结果:

6.5 hash的使用

hash.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <sw/redis++/redis++.h>#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;using sw::redis::Redis;void test1(Redis& redis) {std::cout << "hset 和 hget" << std::endl;redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", std::make_pair("f2", "222"));// hset 能够一次性插入多个 field-value 对!!redis.hset("key", {std::make_pair("f3", "333"),std::make_pair("f4", "444")});vector<std::pair<string, string>> fields = {std::make_pair("f5", "555"),std::make_pair("f6", "666")};redis.hset("key", fields.begin(), fields.end());auto result = redis.hget("key", "f3");if (result) {std::cout << "result: " << result.value() << std::endl;} else {std::cout << "result 无效!" << std::endl;}
}void test2(Redis& redis) {std::cout << "hexits" << std::endl;redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");bool result = redis.hexists("key", "f4");std::cout << "result: " << result << std::endl;
}void test3(Redis& redis) {std::cout << "hdel" << std::endl;redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");long long result = redis.hdel("key", "f1");std::cout << "result: " << result << std::endl;result = redis.hdel("key", {"f2", "f3"});std::cout << "result: " << result << std::endl;long long len = redis.hlen("key");std::cout << "len: " << len << std::endl;
}void test4(Redis& redis) {std::cout << "hkeys 和 hvals" << std::endl;redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");vector<string> fields;auto itFields = std::back_inserter(fields);redis.hkeys("key", itFields);printContainer(fields);vector<string> values;auto itValues = std::back_inserter(values);redis.hvals("key", itValues);printContainer(values);
}void test5(Redis& redis) {std::cout << "hmget 和 hmset" << std::endl;redis.flushall();redis.hmset("key", {std::make_pair("f1", "111"),std::make_pair("f2", "222"),std::make_pair("f3", "333")});vector<std::pair<string, string>> pairs = {std::make_pair("f4", "444"),std::make_pair("f5", "555"),std::make_pair("f6", "666")};redis.hmset("key", pairs.begin(), pairs.end());vector<string> values;auto it = std::back_inserter(values);redis.hmget("key", {"f1", "f2", "f3"}, it);printContainer(values);
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);test5(redis);return 0;
}

hset 和 hget:test1()结果:

hexits:test2()结果:

hdel:test3()结果:

hkeys 和 hvals:test4()结果:

hmget 和 hmset:test5()结果:

6.6 zset的使用

zset.cpp 文件:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <sw/redis++/redis++.h>#include "util.hpp"using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::unordered_map;using sw::redis::Redis;void test1(Redis& redis) {std::cout << "zadd 和 zrange" << std::endl;redis.flushall();redis.zadd("key", "吕布", 99);redis.zadd("key", {std::make_pair("赵云", 98),std::make_pair("典韦", 97)});vector<std::pair<string, double>> members = {std::make_pair("关羽", 95),std::make_pair("张飞", 93)};redis.zadd("key", members.begin(), members.end());// zrange 支持两种主要的风格:// 1. 只查询 member, 不带 score// 2. 查询 member 同时带 score// 关键就是看插入迭代器指向的容器的类型. // 指向的容器只是包含一个 string, 就是只查询 member// 指向的容器包含的是一个 pair, 里面有 string 和 double, 就是查询 member 同时带有 scorevector<string> memberResults;auto it = std::back_inserter(memberResults);redis.zrange("key", 0, -1, it);printContainer(memberResults);vector<std::pair<string, double>> membersWithScore;auto it2 = std::back_inserter(membersWithScore);redis.zrange("key", 0, -1, it2);printContainerPair(membersWithScore);
}void test2(Redis& redis) {std::cout << "zcard" << std::endl;redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);long long result = redis.zcard("key");std::cout << "result: " << result << std::endl;
}void test3(Redis& redis) {std::cout << "zrem" << std::endl;redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);redis.zrem("key", "zhangsan");long long result = redis.zcard("key");std::cout << "result: " << result << std::endl;
}void test4(Redis& redis) {std::cout << "zscore" << std::endl;redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);auto score = redis.zscore("key", "zhangsan");if (score) {std::cout << "score: " << score.value() << std::endl;} else {std::cout << "score 无效" << std::endl;}
}void test5(Redis& redis) {std::cout << "zrank" << std::endl;redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);auto rank = redis.zrank("key", "zhaoliu");if (rank) {std::cout << "rank: " << rank.value() << std::endl;} else {std::cout << "rank 无效" << std::endl;}
}int main() {Redis redis("tcp://127.0.0.1:6379");// test1(redis);// test2(redis);// test3(redis);// test4(redis);test5(redis);return 0;
}

zadd 和 zrange:test1()结果:

zcard:test2()结果:

zrem:test3()结果:

zscore:test4()结果:

zrank:test5()结果:

redis学习打卡🥳

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLM - 大模型 ScallingLaws 的设计 100B 预训练方案(PLM) 教程(5)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145356022 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

HttpClient学习

目录 一、概述 二、HttpClient依赖介绍 1.导入HttpClient4依赖 2.或者导入HttpClient5依赖 3.二者区别 三、HttpClient发送Get请求和Post请求测试 (一)通过HttpClient发送Get请求 (二)通过HttpClient发送Post请求 一、概述 HttpClient是 Apache 软件基金会提供的一…

FAST-DDS and ROS2 RQT connect

reference: FAST-DDS与ROS2通信_ros2 收fastdds的数据-CSDN博客 software version: repositories: foonathan_memory_vendor: type: git url: https://github.com/eProsima/foonathan_memory_vendor.git version: v1.1.0 fastcdr: …

Kafka后台启动命令

#保存日志 nohup ./kafka-server-start.sh ../config/server.properties > /path/to/logfile.log 2>&1 &#不保存日志 nohup ./kafka-server-start.sh ../config/server.properties >/dev/null 2>&1 & nohup: 是一个Unix/Linux命令&#xff0c;用于…

蓝桥杯算法赛第25场月赛

前言 这些题对于我的难度有点大&#xff0c;大家感兴趣的可以来做一下&#xff0c;看一下&#xff0c;下面给大家展示一下题目 1. 桃花运走向【算法赛】 问题描述 2025 年春节&#xff0c;小明和小红兴致勃勃地去庙会玩耍。庙会上&#xff0c;一个算命先生摆摊算命&#xf…

开源先锋DeepSeek-V3 LLM 大语言模型本地调用,打造自己专属 AI 助手

DeepSeek-V3是一个强大的混合专家 (MoE) 语言模型&#xff0c;总共有 671B 个参数。为了实现高效的推理和经济高效的训练&#xff0c;DeepSeek-V3 采用了多头潜在注意力机制 (MLA) 和 DeepSeekMoE 架构&#xff0c;这些架构在 DeepSeek-V2 中得到了彻底的验证。此外&#xff0c…

喜报丨迪捷软件入选2025年浙江省“重点省专”

根据《浙江省经济和信息化厅 浙江省财政厅关于进一步支持专精特新中小企业高质量发展的通知》&#xff08;浙经信企业〔2024〕232号&#xff09;有关要求&#xff0c;经企业自主申报、地方推荐、材料初审以及专家评审等程序&#xff0c;浙江省经济和信息化厅发布了2025年浙江省…

简识JVM中并发垃圾回收器和多线程并行垃圾回收器的区别

在JVM中&#xff0c;多线程并行垃圾回收器和并发垃圾回收器是两种不同类型的垃圾回收机制&#xff0c;它们的主要区别在于垃圾收集线程与用户线程之间的运行关系&#xff0c;以及这种关系对应用程序性能的影响。以下是对这两种垃圾回收器的详细比较&#xff1a; 一、多线程并行…

Golang Gin系列-8:单元测试与调试技术

在本章中&#xff0c;我们将探讨如何为Gin应用程序编写单元测试&#xff0c;使用有效的调试技术&#xff0c;以及优化性能。这包括设置测试环境、为处理程序和中间件编写测试、使用日志记录、使用调试工具以及分析应用程序以提高性能。 为Gin应用程序编写单元测试 设置测试环境…

通过 NAudio 控制电脑操作系统音量

根据您的需求&#xff0c;以下是通过 NAudio 获取和控制电脑操作系统音量的方法&#xff1a; 一、获取和控制系统音量 &#xff08;一&#xff09;获取系统音量和静音状态 您可以使用 NAudio.CoreAudioApi.MMDeviceEnumerator 来获取系统默认音频设备的音量和静音状态&#…

深度学习 Pytorch 单层神经网络

神经网络是模仿人类大脑结构所构建的算法&#xff0c;在人脑里&#xff0c;我们有轴突连接神经元&#xff0c;在算法中&#xff0c;我们用圆表示神经元&#xff0c;用线表示神经元之间的连接&#xff0c;数据从神经网络的左侧输入&#xff0c;让神经元处理之后&#xff0c;从右…

Arduino大师练成手册 --控制 OLED

要在 Arduino 上使用 U8glib 库控制带有 7 个引脚的 SPI OLED 显示屏&#xff0c;你可以按照以下步骤进行&#xff1a; 7pin OLED硬件连接 GND&#xff1a;连接到 Arduino 的 GND 引脚。 VCC&#xff1a;连接到 Arduino 的 5V 引脚。 D0&#xff08;或 SCK/CLK&#xff09;…

水果实体店品牌数字化:RWA + 智能体落地方案

一、方案背景 随着数字化技术的迅猛发展&#xff0c;实体零售行业正面临前所未有的挑战与机遇。传统的零售模式难以满足消费者对个性化、便捷化、智能化的需求&#xff0c;尤其是在水果等生鲜商品领域&#xff0c;如何通过技术手段提升运营效率、增强顾客体验、拓宽盈利模式&a…

业务对象和对象的区别

"业务对象"和"对象"这两个术语在日常编程和软件工程中经常被使用&#xff0c;但它们之间存在一些区别&#xff0c;主要体现在它们的目的、范围和抽象层次上。 ### 对象&#xff08;Object&#xff09; 1. **定义**&#xff1a; - 对象是面向对象编程&#…

三高“高性能、高并发、高可靠”系统架构设计系列文章

目录 高并发系统的艺术&#xff1a;如何在流量洪峰中游刃有余 《数据密集型应用系统设计》读后感与高并发高性能实践案例 系统稳定性与高可用保障的几种思路 软件系统限流的底层原理解析 技术解决方案调研 延迟队列调研 重试调研 异步回调调研 分库分表调研 分布式事…

ray.rllib-入门实践-12:自定义policy

在本博客开始之前&#xff0c;先厘清一下几个概念之间的区别与联系&#xff1a;env, agent, model, algorithm&#xff0c; policy. 强化学习由两部分组成&#xff1a; 环境(env)和智能体(agent)。环境&#xff08;env&#xff09;提供观测值和奖励; agent读取观测值&#x…

CVE-2024-23897-Jenkins任意文件读取漏洞复现

content Jenkins是什么CVE-2024-23897总结修复建议 Jenkins是什么 Jenkins是一人基于Java开发的、可扩展的持续集成引擎&#xff0c;用于持续、自动地构建/测试软件项目&#xff0c;可以监控一些定时执行的任务。 官网文档&#xff1a; Jenkins是一款开源 CI&CD 软件&…

Lua 环境的安装

1.安装Lua运行环境 本人采用的是在windows系统中使用cmd指令方式进行安装&#xff0c;安装指令如下&#xff1a; winget install "lua for windows" 也曾使用可执行程序安装过&#xff0c;但由于电脑是加密电脑&#xff0c;最后都已失败告终。使用此方式安装可以安…

基于微信小程序的网上订餐管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【矩阵二分】力扣378. 有序矩阵中第 K 小的元素

给你一个 n x n 矩阵 matrix &#xff0c;其中每行和每列元素均按升序排序&#xff0c;找到矩阵中第 k 小的元素。 请注意&#xff0c;它是 排序后 的第 k 小元素&#xff0c;而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n2) 的解决方案。 示例 1&#xff1…