通過 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,完整代碼可以在代碼庫中找到。