VWED_server/data/cache.py

285 lines
8.0 KiB
Python
Raw Normal View History

2025-04-30 16:57:46 +08:00
#!/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