VWED_server/data/cache.py
2025-04-30 16:57:46 +08:00

285 lines
8.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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