这篇文章不会讲解所有关于5大基础类型的所有命令,只讲解几个常用的命令操作。如果想看全部的命令操作,可以看其它的文章。
string
set
先来看一看set
操作在服务器端的函数原型:
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
其中有[NX | XX]
选项,而且还能设置过期时间,在通用接口中我们已经见过了函数原型。只是还有2个参数没有讲解,接下来就讲解另外2个参数。
cpp
bool set(const sw::redis::StringView &key,
const sw::redis::StringView &val,
const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
sw::redis::UpdateType type = sw::redis::UpdateType::ALWAYS)
第三个参数用于设置超时时间,第四个参数可以选择设置[NX | XX]
。有三种选项可以选择:
ALWAYS
:默认值是这个。表示的是总是插入新的数据。NOT_EXIST
:key
不存在时才会插入,key
存在时则不设置(返回nil)。与NX
一样。EXIST
:key
存在时则更新(相当于更新key的value),不存在时不会设置。与XX
一样。
代码示例:
cpp
using sw::redis::Redis;
using namespace std;
void test1(Redis &redis)
{
cout << "get 和 set" << std::endl;
redis.flushall();
redis.set("key1", "111");
auto value = redis.get("key1");
if (value)
cout << "value:" << value.value() << endl;
redis.set("key2", "222");
value = redis.get("key2");
if (value)
cout << "value:" << value.value() << endl;
cout << "带上超时时间" << endl;
redis.set("key3", "333", 10s); // 设置10秒后过期
this_thread::sleep_for(3s); // 休眠3秒
long long time = redis.ttl("key3");
cout << "time: " << time << endl;
}

cpp
void test2(Redis &redis)
{
cout << "set NX 和 XX" << endl;
redis.flushall();
redis.set("key1", "111");
// set的重载版本中,没有单独提供NX和XX的版本,必须搭配过期时间版本来使用。
redis.set("key1", "222", 5s, sw::redis::UpdateType::EXIST); // 如果不想设置过期时间的话,写0s就行,不能省略第三个参数
auto value = redis.get("key1");
if (value)
cout << "value: " << value.value() << endl;
else
cout << "key不存在" << endl;
}

mset
用于同时设置多个key
。函数原型如下:
cpp
template <typename Input>
void mset(Input first, Input last);
template <typename T>
void mset(std::initializer_list<T> il) {
mset(il.begin(), il.end());
}
第一个版本是可以使用容器迭代器,类型是std::pair<std::string, std::string>
。例如,可以使用vector
,然后存入pair
;也可以使用map
或者unordered_map
来进行存储。
第二个版本是使用初始化列表,列表中的每个元素都是std::pair<std::string, std::string>
。
- 代码示例:
cpp
void test3(Redis &redis)
{
cout << "mset" << endl;
redis.flushall();
// 使用初始化列表
redis.mset({make_pair("key1", "111"), make_pair("key2", "222")});
// 使用迭代器方法
vector<pair<string, string>> v = {
{"key3", "333"},
{"key4", "444"},
};
redis.mset(v.begin(), v.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;
}
mget
用于同时获取多个key
。函数原型如下:
cpp
template <typename Input, typename Output>
void mget(Input first, Input last, Output output);
template <typename T, typename Output>
void mget(std::initializer_list<T> il, Output output) {
mget(il.begin(), il.end(), output);
}
也有两个版本,一种是使用迭代器类型,把要查询的key
放入到input
容器中,然后输入容器的头尾迭代器。第三个参数是一个output
迭代器,用于接收输出的value
。另一种是使用初始化列表,把要查询的key
放入到列表当中。
- 代码示例:
cpp
void test4(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);
for (auto &elem : result)
{
// 此处预期elem是一个optional类型的元素,打印之前,先判定一下,看是否有效。
if (elem)
cout << elem.value() << endl;
else
cout << "元素无效" << endl;
}
}

getrange
获取指定范围内的字符串
。函数原型如下:
std::string getrange(const StringView &key, long long start, long long end);
第一个参数是需要查看的key
,第二个和第三个参数都是查询的范围,下标可以是负数。
setrange
从指定下标覆盖字符串。函数原型如下:
long long setrange(const StringView &key, long long offset, const StringView &val);
第一个参数是指定的key
;第二个参数是起始的下标,从起始下标往后的字符将被覆盖;第三个参数是用val
进行覆盖。
返回值是此操作后字符串的长度。
- 代码示例:
cpp
void test5(Redis &redis)
{
cout << "getrange" << endl;
redis.flushall();
redis.set("key", "abcdefg");
string result = redis.getrange("key", 2, 5);
cout << "result: " << result << endl;
redis.setrange("key", 2, "ooo");
auto value = redis.get("key");
cout << "value: " << value.value() << endl;
}

incrby
将 key 中储存的数字加上指定的增量值。函数原型如下:
long long incrby(const StringView &key, long long increment);
decrby
将 key 对应的 string 表⽰的数字减去对应的值。函数原型如下:
long long decrby(const StringView &key, long long decrement);
- 代码示例:
cpp
void test6(Redis &redis)
{
cout << "incrby和decrby" << endl;
redis.flushall();
redis.set("key1", "111");
redis.set("key2", "222");
long long result1 = redis.incrby("key1", 10);
long long result2 = redis.decrby("key2", 10);
cout << "result1: " << result1 << endl;
cout << "result2: " << result2 << endl;
}

list
lpush
把元素头插到列表头部。函数原型如下:
cpp
long long lpush(const StringView &key, const StringView &val);
template <typename Input>
long long lpush(const StringView &key, Input first, Input last);
template <typename T>
long long lpush(const StringView &key, std::initializer_list<T> il) {
return lpush(key, il.begin(), il.end());
}
第一个版本很简单,每次只能插入一个元素。
第二个版本是迭代器类型,第三个版本是使用初始化列表。
- 代码示例
cpp
void test1(Redis &redis)
{
cout << "lpush 和 lrange用法" << endl;
redis.flushall();
// 插入单个元素
redis.lpush("key1", "111");
// 插入多个元素,使用初始化列表
redis.lpush("key1", {"222", "333", "444"});
// 使用迭代器
vector<string> val = {"555", "666"};
redis.lpush("key1", val.begin(), val.end());
// 获取元素
vector<string> ans;
auto it = back_inserter(ans);
redis.lrange("key1", 0, -1, it);
for (auto &elem : ans)
{
cout << elem << endl;
}
}

rpush
把元素尾插到列表尾部。函数原型如下:
cpp
long long rpush(const StringView &key, const StringView &val);
template <typename Input>
long long rpush(const StringView &key, Input first, Input last);
template <typename T>
long long rpush(const StringView &key, std::initializer_list<T> il) {
return rpush(key, il.begin(), il.end());
}
使用方法和lpush
一样。
lpop
从头部删除元素。函数原型如下:
cpp
OptionalString lpop(const StringView &key);
此处需要注意返回的是OptionalString
类型,需要进行检查,避免为空。
rpop
从尾部删除元素。函数原型如下:
cpp
OptionalString rpop(const StringView &key);
- 代码示例:
cpp
void test2(Redis &redis)
{
cout << "lpop 和 rpop 用法" << endl;
redis.flushall();
redis.rpush("key1", {"111", "222", "333", "444", "555"});
auto ans = redis.lpop("key1");
if (ans)
cout << "lpop: " << ans.value() << endl;
ans = redis.rpop("key1");
if (ans)
cout << "rpop: " << ans.value() << endl;
ans = redis.lpop("key2");
if (ans)
cout << "lpop: " << ans.value() << endl;
else
cout << "该key不存在" << endl;
}

lrange
获取指定范围内的元素。函数原型如下:
cpp
template <typename Output>
void lrange(const StringView &key, long long start, long long stop, Output output);
指定区间[start, top]
,然后把结果通过output
迭代器输出到容器中。
llen
获取列表的长度。函数原型如下:
cpp
long long llen(const StringView &key);
blpop
阻塞等待,获取头部元素。函数原型如下:
cpp
// 单个key
OptionalStringPair blpop(const StringView &key, long long timeout);
OptionalStringPair blpop(const StringView &key,
const std::chrono::seconds &timeout = std::chrono::seconds{0});
// 迭代器版本
template <typename Input>
OptionalStringPair blpop(Input first, Input last, long long timeout);
template <typename Input>
OptionalStringPair blpop(Input first,
Input last,
const std::chrono::seconds &timeout = std::chrono::seconds{0});
// 初始化列表版本
template <typename T>
OptionalStringPair blpop(std::initializer_list<T> il, long long timeout) {
return blpop(il.begin(), il.end(), timeout);
}
template <typename T>
OptionalStringPair blpop(std::initializer_list<T> il,
const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
return blpop(il.begin(), il.end(), timeout);
}
blpop
有6个重载但其实是同样的功能的不同传参形式而已。对于redis
的等待,其可以传入一个或者多个key
。前两个函数重载就是对单个key
的特化、超时时间可以分为lonng long
类型和std::chrono
类型,所以有两个重载。
blpop
的返回值一个是OptionalStringPair
,第一个成员是key
,表示该数据从哪一个list
得到的,第二个成员OptionalStringPair.value().second
才是获得到的值。
有两种方式可以访问成员,第一种是通过value()
方法获取pair
:
OptionalStringPair.value().first;
OptionalStringPair.value().fsecond;
还有一种是通过->
访问:
OptionalStringPair -> first;
OptionalStringPair -> second;
该函数可能返回一个空值,所以使用之前要检测是否为空。
- 代码示例
cpp
void test3(Redis &redis)
{
using namespace std::chrono_literals;
cout << "blpop 和 brpop 用法" << endl;
redis.flushall();
auto result = redis.blpop({"key", "key2", "key3"}, 10s); // 如果不设置超时时间,那么会一直阻塞住
if (result)
{
std::cout << "key:" << result.value().first << std::endl;
std::cout << "elem:" << result->second << std::endl;
}
else
{
std::cout << "result 无效!" << std::endl;
}
}

brpop
函数原型:
cpp
// 单key版本
OptionalStringPair brpop(const StringView &key, long long timeout);
OptionalStringPair brpop(const StringView &key,
const std::chrono::seconds &timeout = std::chrono::seconds{0});
// 多key,容器迭代器版本
template <typename Input>
OptionalStringPair brpop(Input first, Input last, long long timeout);
template <typename Input>
OptionalStringPair brpop(Input first,
Input last,
const std::chrono::seconds &timeout = std::chrono::seconds{0});
// 多key,初始化列表版本
template <typename T>
OptionalStringPair brpop(std::initializer_list<T> il, long long timeout);
template <typename T>
OptionalStringPair brpop(std::initializer_list<T> il,
const std::chrono::seconds &timeout = std::chrono::seconds{0});
和blpop
一样
set
sadd
往集合中插入元素,或者创建一个集合。函数原型如下:
cpp
long long sadd(const StringView &key, const StringView &member);
template <typename Input>
long long sadd(const StringView &key, Input first, Input last);
template <typename T>
long long sadd(const StringView &key, std::initializer_list<T> il) {
return sadd(key, il.begin(), il.end());
}
第一个版本是一次添加一个元素。第二个版本是迭代器版本。第三个版本是使用初始化列表。
smembers
返回集合中的所有的成员。 不存在的集合 key 被视为空集合。函数原型如下:
cpp
template <typename Output>
void smembers(const StringView &key, Output output);
- 代码示例:
cpp
void test1(Redis &redis)
{
cout << "sadd 和 smembers" << endl;
redis.flushall();
// 一次添加一个
redis.sadd("key1", "111");
// 使用初始化列表
redis.sadd("key1", {"222", "333", "444"});
// 使用迭代器
set<string> elems = {"555", "666", "777"};
redis.sadd("key1", elems.begin(), elems.end());
vector<string> result;
// auto it = back_inserter(result);
// 由于此处set里的元素顺序是固定的,指定一个result.end()或者result.begin()或者其它位置的迭代器,都无所谓
auto it = inserter(result, result.end());
redis.smembers("key1", it);
for (auto &elem : result)
{
cout << "value: " << elem << endl;
}
}

sismember
判断成员元素是否是集合的成员。函数原型:
cpp
bool sismember(const StringView &key, const StringView &member);
scard
返回集合中元素的数量。函数原型如下:
cpp
long long scard(const StringView &key);
- 代码示例:
cpp
void test2(Redis &redis)
{
cout << "scard使用" << endl;
redis.flushall();
redis.sadd("key1", {"111", "222", "333", "444"});
auto ans = redis.scard("key1");
cout << ans << endl;
}

spop
从 set 中删除并返回⼀个或者多个元素。函数原型:
cpp
OptionalString spop(const StringView &key);
template <typename Output>
void spop(const StringView &key, long long count, Output output);
- 代码示例:
cpp
void test3(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;
}
}
sinter
返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。函数原型:
cpp
template <typename Input, typename Output>
void sinter(Input first, Input last, Output output);
template <typename T, typename Output>
void sinter(std::initializer_list<T> il, Output output) {
sinter(il.begin(), il.end(), output);
}
第一个版本是使用迭代器。第二个是使用初始化列表。最后把结果输出到output
迭代器当中。
- 代码示例:
cpp
void test4(Redis &redis)
{
cout << "sinter" << endl;
redis.flushall();
redis.sadd("key1", {"111", "222", "333"});
redis.sadd("key2", {"111", "222", "444"});
set<string> result;
auto it = inserter(result, result.end());
redis.sinter({"key1", "key2"}, it);
for (auto &elem : result)
{
cout << "value: " << elem << endl;
}
}

sinterstore
将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在,则将其覆盖。函数原型:
cpp
long long sinterstore(const StringView &destination, const StringView &key);
template <typename Input>
long long sinterstore(const StringView &destination,
Input first,
Input last);
template <typename T>
long long sinterstore(const StringView &destination,
std::initializer_list<T> il) {
return sinterstore(destination, il.begin(), il.end());
}
重载的第一个参数都是destination
,求出的交集会被存放到这个set
中。第一个重载是对单个set
的特化,后续两个重载分别输入一个迭代器或者初始化列表,内部放要求交集的多个set
。
- 代码示例:
cpp
void test5(Redis &redis)
{
cout << "sinterstore" << endl;
redis.flushall();
redis.sadd("key1", {"111", "222", "333"});
redis.sadd("key2", {"111", "222", "444"});
long long len = redis.sinterstore("key3", {"key1", "key2"});
cout << "len: " << len << endl;
set<string> result;
auto it = inserter(result, result.end());
redis.smembers("key3", it);
for (auto &elem : result)
{
cout << "value: " << elem << endl;
}
}

hash
hset
用于为哈希表中的字段赋值 。如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。如果字段已经存在于哈希表中,旧值将被覆盖。函数原型:
cpp
long long hset(const StringView &key, const StringView &field, const StringView &val);
long long hset(const StringView &key, const std::pair<StringView, StringView> &item);
template <typename Input>
auto hset(const StringView &key, Input first, Input last)
-> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type;
template <typename T>
long long hset(const StringView &key, std::initializer_list<T> il);
前2个版本是单个键值对。后两个版本是插入多个键值对。
hget
用于返回哈希表中指定字段的值。函数原型:
cpp
OptionalString hget(const StringView &key, const StringView &field);
- 代码示例:
cpp
void test1(Redis &redis)
{
cout << "hget 和 hset" << endl;
redis.flushall();
redis.hset("key1", "f1", "111");
redis.hset("key1", make_pair("f2", "222"));
// 一次性插入多个键值对
redis.hset("key1", {make_pair("f3", "333"), make_pair("f4", "444")});
vector<pair<string, string>> fields = {make_pair("f5", "555"), make_pair("f6", "666")};
redis.hset("key1", fields.begin(), fields.end());
auto ans = redis.hget("key1", "f3");
if (ans)
cout << "ans: " << ans.value() << endl;
else
cout << "ans无效!" << endl;
}

hexists
用于查看哈希表的指定字段是否存在。函数原型:
cpp
bool hexists(const StringView &key, const StringView &field);
hdel
用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。函数原型:
cpp
long long hdel(const StringView &key, const StringView &field);
template <typename Input>
long long hdel(const StringView &key, Input first, Input last);
template <typename T>
long long hdel(const StringView &key, std::initializer_list<T> il) {
return hdel(key, il.begin(), il.end());
}
- 代码示例:
cpp
void test2(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;
}

hkeys
用于获取哈希表中的所有域(field)。函数原型:
cpp
template <typename Output>
void hkeys(const StringView &key, Output output);
hvals
返回哈希表所有的值。函数原型:
cpp
template <typename Output>
void hvals(const StringView &key, Output output);
- 代码示例:
cpp
void test3(Redis &redis)
{
cout << "hkeys 和 hvals" << endl;
redis.flushall();
redis.hset("key1", "f1", "111");
redis.hset("key1", "f2", "222");
redis.hset("key1", "f3", "333");
vector<string> fields;
auto itfie = back_inserter(fields);
redis.hkeys("key1", itfie);
for (auto &elem : fields)
{
cout << "value: " << elem << endl;
}
vector<string> values;
auto itval = back_inserter(values);
redis.hvals("key1", itval);
for (auto &elem : values)
{
cout << "value: " << elem << endl;
}
}

hmget
用于返回哈希表中,一个或多个给定字段的值。如果指定的字段不存在于哈希表,那么返回一个 nil 值。函数原型:
cpp
template <typename T, typename Output>
void hmget(const StringView &key, std::initializer_list<T> il, Output output) {
hmget(key, il.begin(), il.end(), output);
}
template <typename Input, typename Output>
void hmget(const StringView &key, Input first, Input last, Output output);
hmset
用于同时将多个 field-value (字段-值)对设置到哈希表中。此命令会覆盖哈希表中已存在的字段。如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作。函数原型:
cpp
template <typename Input>
void hmset(const StringView &key, Input first, Input last);
template <typename T>
void hmset(const StringView &key, std::initializer_list<T> il) {
hmset(key, il.begin(), il.end());
}
- 代码示例:
cpp
void test4(Redis &redis)
{
cout << "hmget 和 hmset" << endl;
redis.flushall();
redis.hmset("key", {make_pair("f1", "111"),
make_pair("f2", "222"),
make_pair("f3", "333")});
vector<pair<string, string>> pairs = {
make_pair("f4", "444"),
make_pair("f5", "555"),
make_pair("f6", "666")};
redis.hmset("key", pairs.begin(), pairs.end());
vector<string> values;
auto it = back_inserter(values);
redis.hmget("key", {"f1", "f2", "f3"}, it);
for (auto &elem : values)
{
cout << "value: " << elem << endl;
}
}

zset
zadd
往zset中插入元素。函数原型如下:
cpp
long long zadd(const StringView &key,
const StringView &member,
double score,
UpdateType type = UpdateType::ALWAYS,
bool changed = false);
template <typename Input>
long long zadd(const StringView &key,
Input first,
Input last,
UpdateType type = UpdateType::ALWAYS,
bool changed = false);
template <typename T>
long long zadd(const StringView &key,
std::initializer_list<T> il,
UpdateType type = UpdateType::ALWAYS,
bool changed = false);
zrange
获取zset指定范围内的元素。函数原型如下:
cpp
template <typename Output>
void zrange(const StringView &key, long long start, long long stop, Output output);
zrange
支持两种主要的风格:
- 只查询
member
,不带score
。 - 查询
member
同时带score
。
这两种风格关键就是看插入迭代器指向的容器的类型。指向的容器只是一个string
,就是查询member
,指向的容器包含的是一个pair
,里面有string
和double
,就是查询member
同时带有string
。
- 代码示例:
cpp
void test1(Redis &redis)
{
cout << "zadd 和 zrange" << endl;
redis.flushall();
redis.zadd("key1", "吕布", 99);
redis.zadd("key1", {make_pair("赵云", 98), make_pair("典韦", 97)});
vector<pair<string, double>> members = {make_pair("关羽", 95), make_pair("张飞", 93)};
redis.zadd("key1", members.begin(), members.end());
// 只查询members
vector<string> memberRedults;
auto it = back_inserter(memberRedults);
redis.zrange("key1", 0, -1, it);
for (auto &elem : memberRedults)
cout << "members: " << elem << endl;
// 查询member和score
vector<pair<string, double>> memberWithScore;
auto it2 = back_inserter(memberWithScore);
redis.zrange("key1", 0, -1, it2);
for (const auto &elem : memberWithScore)
cout << elem.first << ":" << elem.second << endl;
}

zcard
获取zset
中的元素个数,函数原型如下:
cpp
long long zcard(const StringView &key);
- 代码示例:
cpp
void test2(Redis &redis)
{
cout << "zcard" << endl;
redis.flushall();
redis.zadd("key1", "吕布", 99);
redis.zadd("key1", {make_pair("赵云", 98), make_pair("典韦", 97)});
auto ans = redis.zcard("key1");
cout << ans << endl;
}

zrem
删除zset中的元素。函数原型如下:
cpp
long long zrem(const StringView &key, const StringView &member);
template <typename Input>
long long zrem(const StringView &key, Input first, Input last);
template <typename T>
long long zrem(const StringView &key, std::initializer_list<T> il) {
return zrem(key, il.begin(), il.end());
}
- 代码示例:
cpp
void test3(Redis &redis)
{
cout << "zrem" << endl;
redis.flushall();
redis.zadd("key1", "张三", 90);
redis.zadd("key1", "李四", 92);
redis.zadd("key1", "王五", 93);
redis.zadd("key1", "赵六", 88);
redis.zrem("key1", "李四");
long long ans = redis.zcard("key1");
cout << ans << endl;
}

zscore
获取member
的score
。函数原型如下:
cpp
OptionalDouble zscore(const StringView &key, const StringView &member);
zrank
获取member
的排名,函数原型如下:
cpp
OptionalLongLong zrank(const StringView &key, const StringView &member);
- 代码示例:
cpp
void test4(Redis &redis)
{
cout << "zscore 和 zrank" << endl;
redis.flushall();
redis.zadd("key1", "张三", 90);
redis.zadd("key1", "李四", 92);
redis.zadd("key1", "王五", 93);
redis.zadd("key1", "赵六", 88);
auto score = redis.zscore("key1", "王五");
if (score)
cout << "score: " << score.value() << endl;
else
cout << "score无效" << endl;
auto rank = redis.zrank("key1", "赵六");
if (rank)
cout << "rank: " << rank.value() << endl;
else
cout << "rank 无效" << endl;
}
