1 个不稳定版本

0.15.2-alpha.02020年4月27日

#2167数据库接口

32 每月下载量
thruster-socketio 中使用

BSD-3-Clause

265KB
5K SLoC

redis-rs

*注意:这不是 Redis-RS 的最佳版本 -- 这是为了发布而分叉的版本,因为主分支的开发似乎暂时停止了。请访问此处获取原始版本: redis-rs.

安装,请在 crates.io 上安装 trezm-redis


lib.rs:

redis-rs 是一个 Redis 客户端库的 Rust 实现。它公开了一个通用接口用于 Redis,并且还提供了对常用功能的特定帮助。

该包名为 redis,您可以通过 cargo 依赖它

[dependencies.redis]
version = "*"

如果您想使用 git 版本

[dependencies.redis]
git = "https://github.com/mitsuhiko/redis-rs.git"

基本操作

redis-rs 暴露了两个 API 级别:一个低级别和一个高级部分。高级部分不公开 redis 的所有功能,并且可能在如何使用协议方面采取一些自由行动。API 的低级部分允许您在 Redis 层面上表达任何请求。您可以在任何位置流畅地在两个 API 级别之间切换。

连接处理

要连接到 redis,您可以使用客户端对象,然后它将产生实际连接。连接和客户端以及连接和客户端的结果被认为是 ConnectionLike 对象,可以在请求的任何地方使用。

获取连接的完整规范方式是创建一个客户端并从它那里请求一个连接

extern crate redis;

fn do_something() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1/")?;
    let mut con = client.get_connection()?;

    /* do something here */

    Ok(())
}

可选功能

定义了一些功能,如果需要,可以启用附加功能。其中一些默认启用。

  • aio:启用异步 IO 支持(默认启用)
  • geospatial:启用地理空间支持(默认启用)
  • script:启用脚本支持(默认启用)
  • r2d2:启用 r2d2 连接池支持(可选)
  • cluster:启用 Redis 集群支持(可选)
  • tokio-rt-core:启用对 tokio-rt 的支持(可选)
  • connection-manager:启用自动重连支持(可选)

连接参数

redis-rs 知道如何定义连接应该去哪里。在 Client::open 的参数需要实现 IntoConnectionInfo trait,该 trait 有三种实现。

  • redis:// URL 格式中的字符串切片。
  • 来自 redis-url crate 的 URL 对象。
  • ConnectionInfo 对象。

URL 格式为 redis://[:<passwd>@]<hostname>[:port][/<db>]

如果支持 Unix 套接字,则可以使用此格式的 Unix URL。

redis+unix:///[:<passwd>@]<path>[?db=<db>]

为了与某些其他 redis 库兼容,也支持 "unix" 方案。

unix:///[:<passwd>@]<path>[?db=<db>]

执行低级命令

要执行低级命令,可以使用 cmd 函数,该函数允许您构建 redis 请求。一旦您按照喜好配置了命令对象,就可以将查询发送到任何 ConnectionLike 对象。

fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
    let _ : () = redis::cmd("SET").arg("my_key").arg(42).query(con)?;
    Ok(())
}

查询时返回的结果是一个结果对象。如果您不关心实际的返回值(除了它不是失败之外),您始终可以将它类型注解为单元类型 ()

执行高级命令

高级接口类似。为了使其可用,您需要使用 Commands trait,在这种情况下,库提供的所有 ConnectionLike 对象也将具有高级方法,这使得处理协议更加容易。

extern crate redis;
use redis::Commands;

fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
    let _ : () = con.set("my_key", 42)?;
    Ok(())
}

请注意,高级命令仍在开发中,许多命令仍然缺失!

类型转换

由于 redis 本质上大部分是无类型的,且协议对开发者来说并不友好,因此此库提供了灵活的支持,以将值转换为预期的结果。这是通过 FromRedisValueToRedisArgs trait 实现的。

命令的 arg 方法将通过 ToRedisArgs trait 接受广泛类型的参数,而命令的 query 方法可以通过 FromRedisValue trait 将值转换为函数预期的返回值。这非常灵活,允许向量、元组、哈希集、哈希表以及可选值。

let count : i32 = con.get("my_counter")?;
let count = con.get("my_counter").unwrap_or(0i32);
let k : Option<String> = con.get("missing_key")?;
let name : String = con.get("my_name")?;
let bin : Vec<u8> = con.get("my_binary")?;
let map : HashMap<String, i32> = con.hgetall("my_hash")?;
let keys : Vec<String> = con.hkeys("my_hash")?;
let mems : HashSet<i32> = con.smembers("my_set")?;
let (k1, k2) : (String, String) = con.get(&["k1", "k2"])?;

迭代协议

除了发送单个查询外,还支持迭代器。当与常规批量响应一起使用时,它们在查询和转换为向量(两者都使用向量内部)方面不会给您带来太多好处,但它们也可以与 SCAN 类型的命令一起使用,在这种情况下,迭代将发送更多查询,直到游标耗尽。

let mut iter : redis::Iter<isize> = redis::cmd("SSCAN").arg("my_set")
    .cursor_arg(0).clone().iter(&mut con)?;
for x in iter {
    // do something with the item
}

如您所见,游标参数需要使用 cursor_arg 而不是 arg 来定义,以便库知道哪个参数需要在查询运行更多项时更新。

流水线

除了简单的查询外,还可以发送命令流水线。这是通过 pipe 函数提供的。它的工作方式与发送单个命令非常相似,但您可以在一次操作中发送多个命令。这也允许您忽略单个结果,以便更容易匹配最终结果。

let (k1, k2) : (i32, i32) = redis::pipe()
    .cmd("SET").arg("key_1").arg(42).ignore()
    .cmd("SET").arg("key_2").arg(43).ignore()
    .cmd("GET").arg("key_1")
    .cmd("GET").arg("key_2").query(&mut con)?;

如果您想将流水线包装在 MULTI/EXEC 块中,您可以很容易地将流水线切换到 atomic 模式。从调用者的角度来看,没有任何变化,流水线本身将为您处理其余部分。

let (k1, k2) : (i32, i32) = redis::pipe()
    .atomic()
    .cmd("SET").arg("key_1").arg(42).ignore()
    .cmd("SET").arg("key_2").arg(43).ignore()
    .cmd("GET").arg("key_1")
    .cmd("GET").arg("key_2").query(&mut con)?;

您还可以在流水线上使用高级命令。

let (k1, k2) : (i32, i32) = redis::pipe()
    .atomic()
    .set("key_1", 42).ignore()
    .set("key_2", 43).ignore()
    .get("key_1")
    .get("key_2").query(&mut con)?;

事务

事务可以通过原子管道进行操作。为了更简单地使用它们,您可以使用连接的 transaction 函数。

use redis::Commands;
let key = "the_key";
let (new_val,) : (isize,) = redis::transaction(&mut con, &[key], |con, pipe| {
    let old_val : isize = con.get(key)?;
    pipe
        .set(key, old_val + 1).ignore()
        .get(key).query(con)
})?;
println!("The incremented number is: {}", new_val);

有关更多信息,请参阅 transaction 函数。

发布/订阅

发布/订阅功能目前正在开发中,但通过 PubSub 连接对象提供。由于 Rust 在 libnative 中尚不支持异步 IO,因此 API 还没有提供任何形式的超时读取消息的方式。

示例用法

let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_connection()?;
let mut pubsub = con.as_pubsub();
pubsub.subscribe("channel_1")?;
pubsub.subscribe("channel_2")?;

loop {
    let msg = pubsub.get_message()?;
    let payload : String = msg.get_payload()?;
    println!("channel '{}': {}", msg.get_channel_name(), payload);
}

依赖关系

~2–14MB
~196K SLoC