【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 软件基金会提供的一…

开源先锋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年浙江省…

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

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

深度学习 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;…

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…

基于微信小程序的助农扶贫系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Linux Futex学习笔记

Futex 简介 概述&#xff1a; Futex(Fast Userspace Mutex)是linux的一种特有机制&#xff0c;设计目标是避免传统的线程同步原语&#xff08;如mutex、条件变量等&#xff09;在用户空间和内核空间之间频繁的上下文切换。Futex允许在用户空间处理锁定和等待的操作&#xff0…

小柯剧场训练营第一期音乐剧演员与第二期报名拉开帷幕!

在当下社会文化浪潮中&#xff0c;小柯剧场凭借其独特的培养模式和“先看戏后买票”的良心举措&#xff0c;已然成为艺术界的一股清流。1月12日&#xff0c;由“第一期免费训练营”优秀学员们所带来的新一代《稳稳的幸福》成功落幕&#xff0c;引起了社会的广泛关注。该活动不仅…

基于迁移学习的ResNet50模型实现石榴病害数据集多分类图片预测

完整源码项目包获取→点击文章末尾名片&#xff01; 番石榴病害数据集 背景描述 番石榴 &#xff08;Psidium guajava&#xff09; 是南亚的主要作物&#xff0c;尤其是在孟加拉国。它富含维生素 C 和纤维&#xff0c;支持区域经济和营养。不幸的是&#xff0c;番石榴生产受到降…

【论文阅读】HumanPlus: Humanoid Shadowing and Imitation from Humans

作者&#xff1a;Zipeng Fu、Qingqing Zhao、Qi Wu、Gordon Wetstein、Chelsea Finn 项目共同负责人&#xff0c;斯坦福大学 项目网址&#xff1a;https://humanoid-ai.github.io 摘要 制造外形与人类相似的机器人的一个关键理由是&#xff0c;我们可以利用大量的人类数据进行…

PVE 虚拟机安装 Debian 无图形化界面服务器

Debian 安装 Debian 镜像下载 找一个Debian镜像服务器&#xff0c;根据需要的版本和自己硬件选择。 iso-cd/&#xff1a;较小&#xff0c;仅包含安装所需的基础组件&#xff0c;可能需要网络访问来完成安装。有镜像 debian-12.9.0-amd64-netinst.isoiso-dvd/&#xff1a;较…

硬件学习笔记--35 AD23的使用常规操作

原理图设计 1&#xff09;新建原理图&#xff0c;File-new-Schematic。相关设置参考&#xff0c;主要包含图纸设置以及常规的工具栏。 PCB的设计 新建PCB&#xff0c;设置相应的规则&#xff08;与原理图中相对应&#xff09;&#xff0c;放到同一个工程中。如果有上一版本的…

解读2025年生物医药创新技术:展览会与论坛的重要性

2025生物医药创新技术与应用发展展览会暨论坛&#xff0c;由天津市生物医药行业协会、BIO CHINA生物发酵展组委会携手主办&#xff0c;山东信世会展服务有限公司承办&#xff0c;定于2025年3月3日至5日在济南黄河国际会展中心盛大开幕。展会规模60000平方米、800参展商、35场会…

开始步入达梦中级dba

分析内存使用需要的方法之一 disql /nolog conn sysdba/sysdbaselect value from v$parameter where nameMEMORY_LEAK_CHECK; SP_SET_PARA_VALUE(0,MEMORY_LEAK_CHECK,1); select * from V$MEM_REGINFO; select * from V$MEM_HEAP;