[python]python操作redis(单节点)

294 阅读5分钟

我来详细介绍如何使用Python操作Redis单节点。以下是完整的操作指南:

1. 安装Redis和Python客户端

# 安装Redis(Linux/Mac)
# Ubuntu/Debian
sudo apt-get install redis-server

# Mac
brew install redis

# 启动Redis
redis-server

# 安装Python Redis客户端
pip install redis

2. 基本连接和操作

import redis
import json
from datetime import timedelta

# 连接到Redis单节点
redis_client = redis.Redis(
    host='localhost',     # Redis服务器地址
    port=6379,           # 默认端口
    db=0,                # 数据库编号(0-15)
    password=None,       # 密码(如果有)
    decode_responses=True,  # 自动解码返回字符串
    socket_connect_timeout=5  # 连接超时时间
)

# 或者使用连接池(推荐用于生产环境)
pool = redis.ConnectionPool(
    host='localhost',
    port=6379,
    db=0,
    max_connections=10  # 最大连接数
)
redis_client = redis.Redis(connection_pool=pool)

3. 基本数据操作

String(字符串)类型

# 设置键值对
redis_client.set('name', '张三')
redis_client.setex('token', 3600, 'abc123')  # 设置过期时间(秒)
redis_client.psetex('temp_key', 5000, 'temp_value')  # 毫秒过期

# 获取值
name = redis_client.get('name')
print(name)  # 输出: 张三

# 批量操作
redis_client.mset({'key1': 'value1', 'key2': 'value2'})
values = redis_client.mget('key1', 'key2')

# 数字操作
redis_client.set('counter', 0)
redis_client.incr('counter')      # +1
redis_client.incrby('counter', 5) # +5
redis_client.decr('counter')      # -1

Hash(哈希)类型

# 设置哈希字段
redis_client.hset('user:1001', 'name', '李四')
redis_client.hset('user:1001', 'age', 25)
redis_client.hset('user:1001', 'city', '北京')

# 批量设置
redis_client.hmset('user:1002', {
    'name': '王五',
    'age': 30,
    'email': 'wangwu@example.com'
})

# 获取字段
name = redis_client.hget('user:1001', 'name')
all_fields = redis_client.hgetall('user:1001')

# 删除字段
redis_client.hdel('user:1001', 'city')

# 获取所有字段名
fields = redis_client.hkeys('user:1001')

List(列表)类型

# 从左侧插入
redis_client.lpush('tasks', 'task1', 'task2', 'task3')

# 从右侧插入
redis_client.rpush('tasks', 'task4')

# 获取范围
tasks = redis_client.lrange('tasks', 0, -1)  # 获取所有
first_two = redis_client.lrange('tasks', 0, 1)

# 弹出元素
left_task = redis_client.lpop('tasks')
right_task = redis_client.rpop('tasks')

# 获取列表长度
length = redis_client.llen('tasks')

Set(集合)类型

# 添加元素
redis_client.sadd('tags', 'python', 'redis', 'database')
redis_client.sadd('tags', 'python')  # 重复元素不会添加

# 获取所有成员
all_tags = redis_client.smembers('tags')

# 检查成员是否存在
has_redis = redis_client.sismember('tags', 'redis')

# 集合运算
redis_client.sadd('set1', 'a', 'b', 'c')
redis_client.sadd('set2', 'b', 'c', 'd')

# 交集
intersection = redis_client.sinter('set1', 'set2')

# 并集
union = redis_client.sunion('set1', 'set2')

# 差集
difference = redis_client.sdiff('set1', 'set2')

Sorted Set(有序集合)

# 添加带分数的成员
redis_client.zadd('leaderboard', {
    'player1': 100,
    'player2': 85,
    'player3': 95
})

# 更新分数
redis_client.zincrby('leaderboard', 10, 'player1')

# 获取排名
rank = redis_client.zrevrank('leaderboard', 'player1')  # 从高到低排名
score = redis_client.zscore('leaderboard', 'player1')

# 获取前N名
top_players = redis_client.zrevrange('leaderboard', 0, 2, withscores=True)

# 按分数范围获取
players = redis_client.zrangebyscore('leaderboard', 90, 100)

4. 高级功能

过期时间管理

# 设置过期时间
redis_client.set('session:user1', 'data')
redis_client.expire('session:user1', 1800)  # 30分钟后过期
redis_client.expireat('session:user1', 1672531200)  # 指定时间戳过期

# 获取剩余时间
ttl = redis_client.ttl('session:user1')  # 返回剩余秒数
pttl = redis_client.pttl('session:user1')  # 返回剩余毫秒数

# 持久化(移除过期时间)
redis_client.persist('session:user1')

管道操作(批量执行)

# 使用管道提高性能
pipe = redis_client.pipeline()

pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.incr('counter')
pipe.get('key1')

# 执行所有命令
results = pipe.execute()
print(results)  # [True, True, 1, b'value1']

事务操作

# 使用事务确保原子性
try:
    pipe = redis_client.pipeline(transaction=True)
    
    pipe.watch('balance')  # 监视键
    
    balance = int(redis_client.get('balance') or 0)
    
    if balance >= 100:
        pipe.multi()  # 开始事务
        pipe.decrby('balance', 100)
        pipe.incrby('savings', 100)
        pipe.execute()  # 提交事务
        print("转账成功")
    else:
        print("余额不足")
        pipe.unwatch()
        
except redis.WatchError:
    print("事务执行期间数据被修改,事务已取消")

发布/订阅模式

import threading

# 订阅者
def subscriber():
    pubsub = redis_client.pubsub()
    pubsub.subscribe('news')
    
    for message in pubsub.listen():
        if message['type'] == 'message':
            print(f"收到消息: {message['data']}")

# 发布者
def publisher():
    for i in range(5):
        redis_client.publish('news', f'消息 {i}')
        time.sleep(1)

# 启动线程
threading.Thread(target=subscriber).start()
threading.Thread(target=publisher).start()

5. 实用工具函数

class RedisHelper:
    def __init__(self, host='localhost', port=6379, db=0):
        self.redis_client = redis.Redis(
            host=host,
            port=port,
            db=db,
            decode_responses=True
        )
    
    # 缓存装饰器
    def cache(self, timeout=300):
        def decorator(func):
            def wrapper(*args, **kwargs):
                # 生成缓存键
                cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"
                
                # 尝试从缓存获取
                cached_result = self.redis_client.get(cache_key)
                if cached_result is not None:
                    return json.loads(cached_result)
                
                # 执行函数
                result = func(*args, **kwargs)
                
                # 缓存结果
                self.redis_client.setex(
                    cache_key,
                    timeout,
                    json.dumps(result)
                )
                
                return result
            return wrapper
        return decorator
    
    # 分布式锁
    def acquire_lock(self, lock_name, acquire_timeout=10, lock_timeout=10):
        """获取分布式锁"""
        identifier = str(uuid.uuid4())
        lock_key = f"lock:{lock_name}"
        lock_timeout = int(lock_timeout)
        
        end = time.time() + acquire_timeout
        
        while time.time() < end:
            if self.redis_client.setnx(lock_key, identifier):
                self.redis_client.expire(lock_key, lock_timeout)
                return identifier
            
            if self.redis_client.ttl(lock_key) < 0:
                self.redis_client.expire(lock_key, lock_timeout)
            
            time.sleep(0.001)
        
        return False
    
    def release_lock(self, lock_name, identifier):
        """释放分布式锁"""
        lock_key = f"lock:{lock_name}"
        
        with self.redis_client.pipeline() as pipe:
            while True:
                try:
                    pipe.watch(lock_key)
                    if pipe.get(lock_key) == identifier:
                        pipe.multi()
                        pipe.delete(lock_key)
                        pipe.execute()
                        return True
                    
                    pipe.unwatch()
                    break
                except redis.WatchError:
                    pass
        
        return False
    
    # 限流器
    def rate_limit(self, key, limit, period):
        """限流器"""
        current = self.redis_client.incr(key)
        
        if current == 1:
            self.redis_client.expire(key, period)
        
        return current <= limit

6. 完整示例:用户会话管理

import hashlib
import time

class SessionManager:
    def __init__(self, redis_client):
        self.redis = redis_client
        self.session_prefix = "session:"
        self.session_timeout = 1800  # 30分钟
    
    def create_session(self, user_id, user_data):
        """创建会话"""
        session_id = hashlib.sha256(
            f"{user_id}{time.time()}".encode()
        ).hexdigest()
        
        session_key = f"{self.session_prefix}{session_id}"
        
        # 存储会话数据
        session_data = {
            'user_id': user_id,
            'created_at': time.time(),
            'data': user_data
        }
        
        self.redis.hmset(session_key, session_data)
        self.redis.expire(session_key, self.session_timeout)
        
        return session_id
    
    def get_session(self, session_id):
        """获取会话"""
        session_key = f"{self.session_prefix}{session_id}"
        
        if not self.redis.exists(session_key):
            return None
        
        # 更新过期时间
        self.redis.expire(session_key, self.session_timeout)
        
        return self.redis.hgetall(session_key)
    
    def destroy_session(self, session_id):
        """销毁会话"""
        session_key = f"{self.session_prefix}{session_id}"
        self.redis.delete(session_key)
    
    def update_session_data(self, session_id, data):
        """更新会话数据"""
        session_key = f"{self.session_prefix}{session_id}"
        
        if self.redis.exists(session_key):
            for key, value in data.items():
                self.redis.hset(session_key, key, value)
            return True
        return False

7. 配置和最佳实践

# 配置文件示例
REDIS_CONFIG = {
    'host': 'localhost',
    'port': 6379,
    'db': 0,
    'password': None,
    'socket_timeout': 5,
    'socket_connect_timeout': 5,
    'retry_on_timeout': True,
    'max_connections': 20,
}

# 连接池管理
class RedisManager:
    _pool = None
    
    @classmethod
    def get_client(cls):
        if cls._pool is None:
            cls._pool = redis.ConnectionPool(**REDIS_CONFIG)
        
        return redis.Redis(
            connection_pool=cls._pool,
            decode_responses=True
        )

# 使用
redis_client = RedisManager.get_client()

8. 错误处理

from redis.exceptions import (
    ConnectionError,
    TimeoutError,
    RedisError
)

def safe_redis_operation():
    try:
        # Redis操作
        result = redis_client.get('key')
        return result
    except ConnectionError:
        print("无法连接到Redis服务器")
        # 重试逻辑或使用备用方案
    except TimeoutError:
        print("Redis操作超时")
    except RedisError as e:
        print(f"Redis错误: {e}")
    finally:
        # 清理资源
        pass

注意事项

  1. 连接管理:使用连接池避免频繁创建连接
  2. 序列化:复杂对象需要序列化存储(如使用JSON)
  3. 内存管理:定期清理过期数据,监控内存使用
  4. 错误处理:所有操作都应包含异常处理
  5. 性能优化:使用管道、批量操作提高性能
  6. 键命名规范:使用有意义的键名,如 user:1001:profile

这个指南涵盖了Redis单节点操作的主要方面,你可以根据具体需求选择使用。