285 lines
8.0 KiB
Python
285 lines
8.0 KiB
Python
|
#!/usr/bin/env python
|
|||
|
# -*- coding: utf-8 -*-
|
|||
|
|
|||
|
"""
|
|||
|
缓存管理模块
|
|||
|
提供Redis缓存连接和操作功能
|
|||
|
"""
|
|||
|
|
|||
|
import logging
|
|||
|
import json
|
|||
|
from typing import Any, Optional, Union, Dict, List
|
|||
|
import redis
|
|||
|
|
|||
|
from config.database_config import CacheConfig
|
|||
|
from utils.logger import get_logger
|
|||
|
|
|||
|
# 获取日志记录器
|
|||
|
logger = get_logger("data.cache")
|
|||
|
|
|||
|
|
|||
|
class RedisClient:
|
|||
|
"""Redis客户端,封装常用的Redis操作"""
|
|||
|
|
|||
|
_instance = None
|
|||
|
_redis_client = None
|
|||
|
|
|||
|
def __new__(cls, *args, **kwargs):
|
|||
|
"""单例模式,确保只有一个Redis连接"""
|
|||
|
if cls._instance is None:
|
|||
|
cls._instance = super(RedisClient, cls).__new__(cls)
|
|||
|
return cls._instance
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
"""初始化Redis连接"""
|
|||
|
if self._redis_client is None:
|
|||
|
try:
|
|||
|
self._redis_client = redis.Redis(
|
|||
|
**CacheConfig.get_redis_connection_args()
|
|||
|
)
|
|||
|
logger.info(f"Redis连接已建立:{CacheConfig.REDIS_HOST}:{CacheConfig.REDIS_PORT}/{CacheConfig.REDIS_DB}")
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"Redis连接失败:{str(e)}")
|
|||
|
self._redis_client = None
|
|||
|
|
|||
|
def get_client(self) -> redis.Redis:
|
|||
|
"""获取Redis客户端"""
|
|||
|
return self._redis_client
|
|||
|
|
|||
|
def add_prefix(self, key: str) -> str:
|
|||
|
"""添加键前缀"""
|
|||
|
return f"{CacheConfig.REDIS_PREFIX}{key}"
|
|||
|
|
|||
|
def set(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
|
|||
|
"""
|
|||
|
设置缓存
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
value: 缓存值,如果不是字符串会尝试JSON序列化
|
|||
|
expire: 过期时间(秒)
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 操作是否成功
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return False
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 处理非字符串值
|
|||
|
if not isinstance(value, (str, bytes, int, float)):
|
|||
|
value = json.dumps(value, ensure_ascii=False)
|
|||
|
|
|||
|
# 设置缓存
|
|||
|
self._redis_client.set(prefixed_key, value)
|
|||
|
|
|||
|
# 设置过期时间
|
|||
|
if expire is not None:
|
|||
|
self._redis_client.expire(prefixed_key, expire)
|
|||
|
|
|||
|
return True
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置缓存失败:{str(e)}")
|
|||
|
return False
|
|||
|
|
|||
|
def get(self, key: str, default: Any = None) -> Any:
|
|||
|
"""
|
|||
|
获取缓存
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
default: 默认值(缓存不存在时返回)
|
|||
|
|
|||
|
Returns:
|
|||
|
Any: 缓存值或默认值
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return default
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 获取缓存
|
|||
|
value = self._redis_client.get(prefixed_key)
|
|||
|
|
|||
|
if value is None:
|
|||
|
return default
|
|||
|
|
|||
|
# 尝试JSON反序列化
|
|||
|
try:
|
|||
|
return json.loads(value)
|
|||
|
except (TypeError, json.JSONDecodeError):
|
|||
|
return value
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取缓存失败:{str(e)}")
|
|||
|
return default
|
|||
|
|
|||
|
def delete(self, key: str) -> bool:
|
|||
|
"""
|
|||
|
删除缓存
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 操作是否成功
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return False
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 删除缓存
|
|||
|
return bool(self._redis_client.delete(prefixed_key))
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"删除缓存失败:{str(e)}")
|
|||
|
return False
|
|||
|
|
|||
|
def exists(self, key: str) -> bool:
|
|||
|
"""
|
|||
|
检查缓存是否存在
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 缓存是否存在
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return False
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 检查缓存
|
|||
|
return bool(self._redis_client.exists(prefixed_key))
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"检查缓存失败:{str(e)}")
|
|||
|
return False
|
|||
|
|
|||
|
def expire(self, key: str, seconds: int) -> bool:
|
|||
|
"""
|
|||
|
设置缓存过期时间
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
seconds: 过期时间(秒)
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 操作是否成功
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return False
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 设置过期时间
|
|||
|
return bool(self._redis_client.expire(prefixed_key, seconds))
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置缓存过期时间失败:{str(e)}")
|
|||
|
return False
|
|||
|
|
|||
|
def ttl(self, key: str) -> int:
|
|||
|
"""
|
|||
|
获取缓存剩余过期时间
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
|
|||
|
Returns:
|
|||
|
int: 剩余过期时间(秒),-1表示永不过期,-2表示键不存在
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return -2
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 获取过期时间
|
|||
|
return self._redis_client.ttl(prefixed_key)
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取缓存过期时间失败:{str(e)}")
|
|||
|
return -2
|
|||
|
|
|||
|
def hset(self, key: str, field: str, value: Any) -> bool:
|
|||
|
"""
|
|||
|
设置哈希表字段
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
field: 字段名
|
|||
|
value: 字段值
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 操作是否成功
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return False
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 处理非字符串值
|
|||
|
if not isinstance(value, (str, bytes, int, float)):
|
|||
|
value = json.dumps(value, ensure_ascii=False)
|
|||
|
|
|||
|
# 设置哈希表字段
|
|||
|
self._redis_client.hset(prefixed_key, field, value)
|
|||
|
return True
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置哈希表字段失败:{str(e)}")
|
|||
|
return False
|
|||
|
|
|||
|
def hget(self, key: str, field: str, default: Any = None) -> Any:
|
|||
|
"""
|
|||
|
获取哈希表字段
|
|||
|
|
|||
|
Args:
|
|||
|
key: 缓存键
|
|||
|
field: 字段名
|
|||
|
default: 默认值(字段不存在时返回)
|
|||
|
|
|||
|
Returns:
|
|||
|
Any: 字段值或默认值
|
|||
|
"""
|
|||
|
try:
|
|||
|
if self._redis_client is None:
|
|||
|
return default
|
|||
|
|
|||
|
# 添加前缀
|
|||
|
prefixed_key = self.add_prefix(key)
|
|||
|
|
|||
|
# 获取哈希表字段
|
|||
|
value = self._redis_client.hget(prefixed_key, field)
|
|||
|
|
|||
|
if value is None:
|
|||
|
return default
|
|||
|
|
|||
|
# 尝试JSON反序列化
|
|||
|
try:
|
|||
|
return json.loads(value)
|
|||
|
except (TypeError, json.JSONDecodeError):
|
|||
|
return value
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取哈希表字段失败:{str(e)}")
|
|||
|
return default
|
|||
|
|
|||
|
|
|||
|
# 导出Redis客户端单例
|
|||
|
redis_client = RedisClient()
|
|||
|
|
|||
|
|
|||
|
def get_cache():
|
|||
|
"""获取Redis客户端"""
|
|||
|
return redis_client
|