网上关于redis的介绍,很多理论性的内容了,但是当我想要真正在编程中使用redis时才发现对于初学者而言,理论到实践还是有很大的跨度的。首先第一步,我如何找到合适的库,或者自己写轮子去使用?
redis本质是对内存中数据的管理,它本身也是一个程序。 所以,从代码层面使用redis,就是使用编码语言调用redis的API 和redis进行网络通讯。
python的使用方式,请参考我redis专栏中的另一篇文章。这里不再赘述。相比更简单直观的python ,c++使用redis的方式更加细致划分。这里我们介绍两个库:cpp_redis、 hiredis
首先介绍两个库:
cpp_redis 和 hiredis 都是 Redis 的客户端库,它们通过网络协议与Redis服务器进行通信,使用的是Redis提供的API。
具体来说,cpp_redis 和 hiredis 在操作系统层面上与Redis进行通信的方式有所不同:
cpp_redis
cpp_redis 是C++语言编写的Redis客户端库,基于 Boost.Asio 网络库实现。它通过 TCP/IP 协议连接Redis服务器,并使用Redis提供的协议与服务器进行通信。cpp_redis 支持异步和同步两种模式,可以通过回调函数或者 Future 对象获取结果。
hiredis
hiredis 是C语言编写的Redis客户端库,它使用标准的 socket API进行网络通信。hiredis支持同步和异步两种模式,同步模式下会阻塞调用线程直到操作完成,而异步模式则需要设置回调函数来获取结果。hiredis支持多个Redis服务器的负载均衡,可以自动切换到可用的服务器。
另外对于技术选型请参考作者以下经验:
cpp_redis和hiredis都是Redis的C++客户端库,它们都提供了类似的API来访问Redis服务器。但是它们之间也有一些区别,如下:
技术架构:cpp_redis基于Boost.Asio实现异步I/O,而hiredis则使用了自己的事件处理机制。
可移植性:cpp_redis旨在提供跨平台支持,因为它可以在Windows和Linux系统上运行,而hiredis则更专注于Unix-like系统。
API设计:cpp_redis的API采用模板和lambda表达式,比较现代化;hiredis则使用传统的C函数调用方式。
功能特性:cpp_redis集成了Redis Sentinel和Cluster模式的支持,而hiredis仅限于普通模式。
性能表现:两个库的性能相当,但cpp_redis应该会更快一些,因为它使用了异步I/O,这样可以更高效地利用底层套接字。
总之,两个库都非常优秀,选择哪一个取决于你的需求和偏好。如果你需要更丰富的功能支持和跨平台兼容性,那么cpp_redis可能是更好的选择;如果你需要更简单和稳定的库,并且只在Unix-like系统上运行,那么hiredis可能更适合你。
那么接下来开始实际的代码介绍:
非基础的高级特性
redis的事务功能
Redis的事务是通过MULTI、EXEC、DISCARD和WATCH四个命令实现的,其中MULTI和EXEC必须成对使用。
下面是一个简单的C++代码示例,说明如何使用Redis的事务特性:
#include <iostream> #include <cstring> #include <hiredis/hiredis.h> int main() { redisContext *c = redisConnect("127.0.0.1", 6379); if (c == NULL || c->err) { std::cerr << "Connection error: " << c->errstr << std::endl; return 1; } // 开始事务 redisReply *reply = (redisReply*)redisCommand(c, "MULTI"); freeReplyObject(reply); // 执行多个命令 reply = (redisReply*)redisCommand(c, "SET key1 value1"); freeReplyObject(reply); reply = (redisReply*)redisCommand(c, "SET key2 value2"); freeReplyObject(reply); // 提交事务并获取结果 reply = (redisReply*)redisCommand(c, "EXEC"); if (reply == NULL || reply->type != REDIS_REPLY_ARRAY) { std::cerr << "Transaction error: " << c->errstr << std::endl; return 1; } // 输出结果 for (size_t i = 0; i < reply->elements; i++) { std::cout << "Result " << i << ": " << reply->element[i]->str << std::endl; } freeReplyObject(reply); // 关闭连接 redisFree(c); return 0; }
在上面的代码中,我们首先使用redisConnect()函数连接到本地Redis实例。然后,我们使用MULTI命令开启一个新的事务,并依次执行两个SET命令以将两个键值对存储在Redis中。最后,我们使用EXEC命令提交事务并获取结果。
需要注意的是,如果在事务执行期间有其他客户端修改了被WATCH命令监视的键,则提交事务时Redis将返回一个错误响应,事务中所有的操作都将被回滚。例如:
// 开始事务 reply = (redisReply*)redisCommand(c, "MULTI"); freeReplyObject(reply); // 监视 key1 reply = (redisReply*)redisCommand(c, "WATCH key1"); freeReplyObject(reply); // 开始另一个客户端修改 key1 // ... // ... // 尝试修改 key1 reply = (redisReply*)redisCommand(c, "SET key1 value1_new"); freeReplyObject(reply); // 提交事务,因为 key1 被其他客户端修改,所以这里会返回一个错误响应 reply = (redisReply*)redisCommand(c, "EXEC"); if (reply == NULL || reply->type != REDIS_REPLY_ERROR) { std::cerr << "Transaction error: " << c->errstr << std::endl; return 1; }
Redis是一种高性能的键值存储数据库,除了基本的读写操作,还有以下特性:
发布/订阅功能:
Redis支持发布/订阅模式,可以通过PUBLISH命令向指定频道发布消息,SUBSCRIBE命令可以订阅频道并接收到发布的消息。
下面是使用C++ Redis客户端库cpp_redis示例代码展示如何进行发布和订阅:
#include #include int main() { cpp_redis::subscriber sub; sub.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::subscriber::connect_state status) { if (status == cpp_redis::subscriber::connect_state::dropped) { std::cout << "client disconnected from " << host << ":" << port << std::endl; } }); sub.subscribe("my_channel", [](const std::string& channel, const std::string& msg) { std::cout << "Received message: " << msg << " on channel: " << channel << std::endl; }); sub.commit(); cpp_redis::publisher pub; pub.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::publisher::connect_state status) { if (status == cpp_redis::publisher::connect_state::dropped) { std::cout << "client disconnected from " << host << ":" << port << std::endl; } }); pub.publish("my_channel", "Hello world!"); pub.commit(); return 0; }
Lua脚本支持:
Redis支持Lua脚本,可以通过EVAL和EVALSHA命令执行Lua脚本。下面是一个示例,将数字递增1并返回结果:
#include #include int main() { cpp_redis::client client; client.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) { if (status == cpp_redis::client::connect_state::dropped) { std::cout << "client disconnected from " << host << ":" << port << std::endl; } }); // 将数字递增1并返回结果 client.eval("return redis.call('INCR', 'mykey')", [](cpp_redis::reply& reply) { std::cout << "Result: " << reply.as_integer() << std::endl; }); client.sync_commit(); return 0; }
过期时间:
Redis支持设置键的过期时间,可以通过EXPIRE命令设置键的过期时间(秒),也可以通过PEXPIRE命令设置毫秒级别的过期时间。
下面是一个示例代码,将键的过期时间设置为10秒:
#include #include int main() { cpp_redis::client client; client.connect("127.0.0.1", 6379, [](const std::string& host, std::size_t port, cpp_redis::client::connect_state status) { if (status == cpp_redis::client::connect_state::dropped) { std::cout << "client disconnected from " << host << ":" << port << std::endl; } }); // 将键设置为123,并设置过期时间为10秒 client.set("mykey", "123"); client.expire("mykey", 10); client.sync_commit(); return 0; }
基础的数据结构读写方式
1字符串类型
Redis 中字符串类型的基本操作包括 SET、GET、INCR、DECR 等。例如,可以使用以下 C++ 代码来设置和获取字符串类型的键值对:
redisReply* reply = static_cast(redisCommand(context, "SET key value")); freeReplyObject(reply); reply = static_cast(redisCommand(context, "GET key")); std::cout << "value: " << reply->str << std::endl; freeReplyObject(reply);
2.哈希表类型
Redis 中哈希表类型的基本操作包括 HSET、HGET、HDEL、HLEN 等。例如,可以使用以下 C++ 代码来设置和获取哈希表类型的键值对:
redisReply* reply = static_cast(redisCommand(context, "HSET hash key value")); freeReplyObject(reply); reply = static_cast(redisCommand(context, "HGET hash key")); std::cout << "value: " << reply->str << std::endl; freeReplyObject(reply);
3.列表类型
Redis 中列表类型的基本操作包括 LPUSH、RPUSH、LPOP、RPOP、LLEN 等。例如,可以使用以下 C++ 代码来设置和获取列表类型的值:
redisReply* reply = static_cast(redisCommand(context, "LPUSH list value1")); freeReplyObject(reply); reply = static_cast(redisCommand(context, "LPUSH list value2")); reply = static_cast(redisCommand(context, "LRANGE list 0 -1")); for (int i = 0; i < reply->elements; ++i) { std::cout << "value: " << reply->element[i]->str << std::endl; } freeReplyObject(reply);
4.
集合类型
Redis 中集合类型的基本操作包括 SADD、SREM、SMEMBERS、SISMEMBER、SCARD 等。例如,可以使用以下 C++ 代码来设置和获取集合类型的值:
redisReply* reply = static_cast(redisCommand(context, "SADD set value1")); freeReplyObject(reply); reply = static_cast(redisCommand(context, "SADD set value2")); reply = static_cast(redisCommand(context, "SMEMBERS set")); for (int i = 0; i < reply->elements; ++i) { std::cout << "value: " << reply->element[i]->str << std::endl; } freeReplyObject(reply);
5.有序集合类型
Redis 中有序集合类型的基本操作包括 ZADD、ZREM、ZRANGE、ZSCORE、ZCARD 等。例如,可以使用以下 C++ 代码来设置和获取有序集合类型的值:
redisReply* reply = static_cast(redisCommand(context, "ZADD zset 1 value1")); freeReplyObject(reply); reply = static_cast(redisCommand(context, "ZADD zset 2 value2")); reply = static_cast(redisCommand(context, "ZRANGE zset 0 -1")); for (int i = 0; i < reply->elements; ++i) { std::cout << "value: " << reply->element[i]->str << std::endl; } freeReplyObject(reply);
服务器高级架构体系:https://xxetb.xet.tech/s/4DEnTI