通过 redis-rs 这个 crate,可以很方便的操作 redis。它提供了同步和异步两种连接,由于我们要集成到 axum 中,所以这里使用异步连接。本章将展示如何获取 redis 异步连接、如何将字符串保存到 redis、如何获取到保存在 redis 里的字符串以及如何通过 redis 保存和读取自定义结构体。
获取 redis 异步连接
redis 默认端口是 6379,由于作者使用 docker 运行了多个 redis 实例,所以示例代码中可能不是redis默认端口。请根据你自身的环境将连接字符串中的主机和端口等信息进行修改。
通过 redis::Client::open()方法可以建立与 redis 服务器的连接,然后使用get_async_connection()方法获取到异步连接。
let client = Client::open("redis://127.0.0.1:16379/").unwrap(); let conn = client .get_async_connection() .await .unwrap();
其中的连接字符串(open()函数的参数)有以下几种写法(中括号内的为可选参数,尖括号内的为必填参数):
redis://[<用户名>][:<密码>@]<主机名>[:端口][/数据库]
unix:///<路径>[?db=<数据库>][&pass=<密码>][&user=<用户名>]
redis+unix:///<路径>[?db=<数据库>][&pass=<密码>][&user=<用户名>]
假如url的方式没有用户名怎么办?
redis的默认用户名就是default, 也可以用如下写法, 直接不写用户名, 用个冒号隔开就算完事:
redis://:{密码}@{主机名}:{端口}/数据库
假如密码里含有#之类的特殊字符怎么办?
自行百度用在线urlencode工具把密码转义一下再放进去。注意不要把冒号圈A之类的必要分隔符号给转义了, 不然你也连不上。
将字符串保存到 redis
调用异步连接的set()方法,可以将字符串保存到 redis:
conn.set("键名","值").await;
示例代码如下:
async fn set() -> Result<&'static str, String> { let client = Client::open(REDIS_DSN).map_err(|err| err.to_string()); let mut conn = client .get_async_connection() .await .map_err(|err| err.to_string()); conn.set("author", "axum.rs") .await .map_err(|err| err.to_string()); Ok("Successfully set") }
读取保存在 redis 中的字符串
异步连接的get()方法,用于从 redis 中获取指定键的数据:
let value = conn.get("键名").await;
示例代码如下:
use redis::{FromRedisValue, RedisResult}; async fn get() -> Result<String, String> { let client = Client::open(REDIS_DSN).map_err(|err| err.to_string())?; let mut conn = client .get_async_connection() .await .map_err(|err| err.to_string()); let somevalue = redis::cmd("GET").arg("some").query_async(&mut conn).await.map_err(|err| err.to_string()).unwrap(); // 判断数据类型, 同时起到了判断当前key是否存在的作用 match &somevalue { redis::Value::Nil => println!("{}", String::new()), // 初始化空字符串代替redis的Nil some => { // redis数据类型转为rust可用类型 let some1: String = FromRedisValue::from_redis_value(some).unwrap(); }, } Ok(somevalue) }
由于 redis 保存的是自己搞的底层数据,你需要转化成rust可用的数据, 你得根据需要将读取到的数据进行类型转换,官方文档有个redis::FromRedisValue的trait可以用。链接在此:
https://docs.rs/redis/latest/redis/trait.FromRedisValue.html
自定义结构体和 redis
了解完字符串的读写操作,我们继续讨论在 redis 读写自定义结构体。
定义数据结构
#[derive(Serialize, Deserialize)]pub struct UserInfo { pub id: i32, pub username: String, pub email: String,
}
将自定义结构体写入 redis 服务器
我们需要将结构体序列化为字符串,然后再写入 redis 服务器:
async fn set_user() -> Result<&'static str, String> { let client = Client::open(REDIS_DSN).map_err(|err| err.to_string())?; let mut conn = client .get_async_connection() .await .map_err(|err| err.to_string())?; let user = UserInfo { id: 1, username: "axum.rs".to_string(), email: "team@axum.rs".to_string(), }; let user = json!(user); conn.set("user", user.to_string()) .await .map_err(|err| err.to_string())?; Ok("Successfully set user.") }
从 redis 中读取自定义结构体
我们需要将 redis 中读取到的字符串反序列化为自定义结构体:
async fn get_user() -> Result<Json<UserInfo>, String> { let client = Client::open(REDIS_DSN).map_err(|err| err.to_string())?; let mut conn = client .get_async_connection() .await .map_err(|err| err.to_string())?; let value: String = conn.get("user").await.map_err(|err| err.to_string())?; let user: UserInfo = from_str(&value).map_err(|err| err.to_string())?; Ok(Json(user)) }
设置自动过期
redis 支持在写入值的时候设置过期时间,时间一到,该数据自动删除:
conn.set_ex("键名","值",过期时间的秒数).await;
本章讨论了如何在 axum 集成 redis,完整代码可以在代码库中找到。