从代码使用角度介绍redis

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis 中有序集合类型的基本操作包括 ZADD、ZREM、ZRANGE、ZSCORE、ZCARD 等。例如,可以使用以下 C++ 代码来设置和获取有序集合类型的值:

网上关于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

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
4月前
|
消息中间件 存储 NoSQL
python 使用redis实现支持优先级的消息队列详细说明和代码
python 使用redis实现支持优先级的消息队列详细说明和代码
69 0
|
5月前
|
缓存 NoSQL PHP
使用PHP-redis实现键空间通知监听key失效事件的技术与代码示例
通过上述方法,你可以有效地在PHP中使用Redis来监听键空间通知,特别是针对键失效事件。这可以帮助你更好地管理缓存策略,及时响应键的变化。
119 3
|
6月前
|
缓存 开发框架 NoSQL
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
|
6月前
|
缓存 监控 NoSQL
【Azure Redis 缓存】使用Python代码获取Azure Redis的监控指标值 (含Powershell脚本方式)
【Azure Redis 缓存】使用Python代码获取Azure Redis的监控指标值 (含Powershell脚本方式)
|
7月前
|
NoSQL Java Redis
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
111 0
|
8月前
|
缓存 NoSQL 安全
玩转Redis!非常强大的Redisson分布式集合,少写60%代码
Redisson是Java的Redis客户端,提供实时数据平台服务,简化了分布式环境下的数据管理。它包含RList、RSet、RMap等分布式集合,支持ConcurrentMap和Set接口,确保线程安全和数据一致性。例如,RMap实现了本地缓存和监听器功能,允许数据监听和本地加速读取。此外,还提供了RSet的排序和去重功能,以及RQueue和RBlockingQueue等队列实现,支持阻塞操作。通过Redisson,开发者能轻松处理分布式系统的数据同步和操作。
|
9月前
|
存储 缓存 NoSQL
[Redis]——缓存击穿和缓存穿透及解决方案(图解+代码+解释)
[Redis]——缓存击穿和缓存穿透及解决方案(图解+代码+解释)
1058 0
|
存储 JSON NoSQL
Redis-使用java代码操作Redis->java连接上redis,java操作redis的常见类型数据存储,redis中的项目应用
Redis-使用java代码操作Redis->java连接上redis,java操作redis的常见类型数据存储,redis中的项目应用
120 0
|
存储 NoSQL Java
Redis ----使用Java代码操作redis(2)
Redis ----使用Java代码操作redis(2)