Skip to main content

mycommon_utils/database/
redis_util.rs

1use redis::{Client, Commands, FromRedisValue, RedisResult, ToRedisArgs};
2use std::num::NonZeroUsize;
3use r2d2::PooledConnection;
4use crate::error::{Error, Result};
5use crate::database::config::REDIS_POOL;
6
7/// Redis 工具类,封装了一些常用的 Redis 操作。
8
9pub struct RedisUtil {
10    connection: PooledConnection<Client>
11}
12
13impl RedisUtil {
14    /// 构造函数,初始化 Redis 客户端。
15    pub fn new() -> Result<RedisUtil> {
16        // 提取配置和连接池,若获取失败则直接返回错误
17        let client = REDIS_POOL.get().ok_or_else(|| {
18            tracing::error!("Failed to get Redis connection pool");
19            Error::NotFound()
20        })?;
21
22        // 获取连接,若失败则记录错误并返回错误
23        let connection = client.get().map_err(|e| {
24            tracing::error!("Failed to obtain Redis connection: {:?}", e);
25            Error::NotFound()
26        })?;
27
28        // 成功获取连接,创建并返回 RedisUtil 实例
29        Ok(RedisUtil {
30            connection
31        })
32    }
33
34    /// 同步设置 Redis 键值对。
35    pub fn set<T: ToRedisArgs>(&mut self, key: &str, value: &T) -> RedisResult<bool> {
36        let result = self.connection.set(key, value)?;
37        Ok(result)
38    }
39
40    /// 同步设置带有过期时间的 Redis 键值对。
41    pub fn set_with_expiry<T: ToRedisArgs>(&mut self, key: &str, value: &T, expiry_seconds: u64) -> RedisResult<()> {
42        let result =self.connection.set_ex(key, value, expiry_seconds)?;
43        Ok(result)
44    }
45
46    /// 设置带 NX 和 EX 的键值对,用于分布式锁
47    pub fn set_nx_ex<T: ToRedisArgs>(&mut self, key: &str, value: &T, expiry_seconds: u64) -> RedisResult<bool> {
48        let mut cmd = redis::Cmd::set(key, value);
49        cmd.arg("NX").arg("EX").arg(expiry_seconds);
50        let result: String = cmd.query(&mut self.connection)?;
51        Ok(result == "OK")
52    }
53
54    /// 同步为现有键设置过期时间。
55    pub fn expire(&mut self, key: &str, expiry_seconds: i64) -> RedisResult<bool> {
56        let result =self.connection.expire(key, expiry_seconds)?;
57        Ok(result)
58    }
59
60    /// 同步获取 Redis 键对应的值。
61    pub fn get<T: FromRedisValue>(&mut self,key: &str) -> RedisResult<Option<T>> {
62        let value: Option<T> = self.connection.get(key)?;
63        Ok(value)
64    }
65
66    /// 使用 Pipeline 进行批量操作(设置多个键值对)。
67    pub fn pipeline_operations<T: ToRedisArgs>(&mut self, keys: Vec<&str>, values: Vec<&T>) -> RedisResult<()> {
68        if keys.len() != values.len() {
69            return Err(redis::RedisError::from((
70                redis::ErrorKind::TypeError,
71                "Keys and values must have the same length",
72            )));
73        }
74        let mut pipe = redis::pipe();
75        for (key, value) in keys.iter().zip(values.iter()) {
76            pipe.set(*key, *value).ignore();
77        }
78        pipe.query::<()>(&mut self.connection)?;
79        Ok(())
80    }
81
82    /// 检查键是否存在。
83    /// 返回 true 表示键存在,false 表示键不存在。
84    pub fn exists(&mut self, key: &str) -> RedisResult<bool> {
85        let exists = self.connection.exists(key)?;
86        Ok(exists)
87    }
88
89    /// 删除一个或多个键。
90    /// 返回删除的键数量。
91    pub fn del_vec(&mut self, keys: Vec<&str>) -> RedisResult<usize> {
92        self.connection.del(keys)
93    }
94    /// 删除一个键。
95    /// 返回删除的键数量。
96    pub fn del(&mut self, key: &str) -> RedisResult<usize> {
97        self.connection.del(key)
98    }
99    /// 获取键的剩余生存时间(TTL),单位为秒。
100    pub fn ttl(&mut self, key: &str) -> RedisResult<isize> {
101        self.connection.ttl(key)
102    }
103
104    /// 对整数类型的键进行原子自增操作。
105    pub fn incr(&mut self, key: &str) -> RedisResult<isize> {
106        self.connection.incr(key, 1)
107    }
108
109    /// 对整数类型的键进行原子自减操作。
110    pub fn decr(&mut self, key: &str) -> RedisResult<isize> {
111        self.connection.decr(key, 1)
112    }
113
114    /// 设置哈希类型的键值对。
115    pub fn hset(&mut self, key: &str, field: &str, value: &str) -> RedisResult<()> {
116        self.connection.hset(key, field, value)
117    }
118
119    /// 获取哈希类型键的值。
120    pub fn hget(&mut self, key: &str, field: &str) -> RedisResult<Option<String>> {
121        self.connection.hget(key, field)
122    }
123
124    /// 向列表左侧推入元素。
125    pub fn lpush<T: FromRedisValue>(&mut self, key: &str, value: &str) -> RedisResult<T> {
126        self.connection.lpush(key, value)
127    }
128
129    /// 从列表右侧弹出元素。
130    pub fn rpop<T: ToString>(&mut self, key: &str, count: Option<usize>) -> RedisResult<Option<Vec<String>>> {
131        let non_zero_count = count.and_then(NonZeroUsize::new);
132        self.connection.rpop(key, non_zero_count)
133    }
134}
135
136// 使用示例:
137// let redis_util = Redis::new().unwrap();
138// redis_util.set("1", "aaa").unwrap();
139// println!("Set value to 'aaa'");