Python 使用 Redis 详细教程

文章目录

Redis 简介

Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,常用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。

安装 Redis 和 Python 客户端

安装 Redis 服务器

Ubuntu/Debian:

bash 复制代码
sudo apt update
sudo apt install redis-server
sudo systemctl start redis
sudo systemctl enable redis

macOS:

bash 复制代码
brew install redis
brew services start redis

Windows:

Redis for Windows 下载安装

安装 Python Redis 客户端

bash 复制代码
pip install redis

连接 Redis

基本连接

python 复制代码
import redis

# 连接到本地 Redis 服务器,默认端口 6379
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 测试连接
try:
    r.ping()
    print("成功连接到 Redis")
except redis.ConnectionError:
    print("无法连接到 Redis")

连接池

python 复制代码
import redis

# 创建连接池
pool = redis.ConnectionPool(
    host='localhost', 
    port=6379, 
    db=0, 
    decode_responses=True,
    max_connections=10
)

# 从连接池获取连接
r = redis.Redis(connection_pool=pool)

# 使用连接
r.set('key', 'value')
print(r.get('key'))

基本操作

字符串操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 设置键值对
r.set('name', 'Alice')
r.set('age', 25)

# 获取值
name = r.get('name')
age = r.get('age')
print(f"Name: {name}, Age: {age}")

# 设置多个键值对
r.mset({'city': 'Beijing', 'country': 'China'})

# 获取多个值
values = r.mget('city', 'country')
print(f"City: {values[0]}, Country: {values[1]}")

# 设置过期时间(秒)
r.setex('temp_key', 60, 'temporary value')  # 60秒后过期

# 检查键是否存在
if r.exists('name'):
    print("键 'name' 存在")

# 删除键
r.delete('temp_key')

# 自增操作
r.set('counter', 0)
r.incr('counter')  # 增加1
r.incrby('counter', 5)  # 增加5
print(f"Counter: {r.get('counter')}")

哈希操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 设置哈希字段
r.hset('user:1000', 'name', 'Bob')
r.hset('user:1000', 'age', 30)
r.hset('user:1000', 'email', 'bob@example.com')

# 获取单个字段
name = r.hget('user:1000', 'name')
print(f"Name: {name}")

# 获取所有字段
user_data = r.hgetall('user:1000')
print(f"User data: {user_data}")

# 设置多个字段
r.hmset('user:1001', {
    'name': 'Charlie',
    'age': 35,
    'email': 'charlie@example.com'
})

# 获取多个字段
fields = r.hmget('user:1001', 'name', 'age')
print(f"Name: {fields[0]}, Age: {fields[1]}")

# 检查字段是否存在
if r.hexists('user:1000', 'email'):
    print("Email 字段存在")

# 删除字段
r.hdel('user:1000', 'email')

# 获取所有字段名
field_names = r.hkeys('user:1001')
print(f"Field names: {field_names}")

# 获取所有字段值
field_values = r.hvals('user:1001')
print(f"Field values: {field_values}")

列表操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 从左侧添加元素
r.lpush('tasks', 'task1', 'task2', 'task3')

# 从右侧添加元素
r.rpush('tasks', 'task4', 'task5')

# 获取列表长度
length = r.llen('tasks')
print(f"Tasks length: {length}")

# 获取列表元素
tasks = r.lrange('tasks', 0, -1)  # 获取所有元素
print(f"All tasks: {tasks}")

# 获取指定范围的元素
first_two = r.lrange('tasks', 0, 1)
print(f"First two tasks: {first_two}")

# 弹出元素
left_task = r.lpop('tasks')
right_task = r.rpop('tasks')
print(f"Left task: {left_task}, Right task: {right_task}")

# 修剪列表,只保留指定范围的元素
r.ltrim('tasks', 0, 2)  # 只保留前3个元素

集合操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 添加元素到集合
r.sadd('tags', 'python', 'redis', 'database', 'cache')

# 获取集合所有成员
tags = r.smembers('tags')
print(f"Tags: {tags}")

# 检查元素是否存在
if r.sismember('tags', 'python'):
    print("Python 在集合中")

# 获取集合元素数量
tag_count = r.scard('tags')
print(f"Tag count: {tag_count}")

# 移除元素
r.srem('tags', 'cache')

# 随机弹出元素
random_tag = r.spop('tags')
print(f"Random tag: {random_tag}")

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

# 交集
intersection = r.sinter('set1', 'set2')
print(f"Intersection: {intersection}")

# 并集
union = r.sunion('set1', 'set2')
print(f"Union: {union}")

# 差集
difference = r.sdiff('set1', 'set2')
print(f"Difference: {difference}")

有序集合操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 添加元素到有序集合
r.zadd('leaderboard', {
    'player1': 1000,
    'player2': 1500,
    'player3': 800,
    'player4': 2000
})

# 获取元素分数
score = r.zscore('leaderboard', 'player1')
print(f"Player1 score: {score}")

# 按分数升序获取元素
players_asc = r.zrange('leaderboard', 0, -1, withscores=True)
print(f"Players (asc): {players_asc}")

# 按分数降序获取元素
players_desc = r.zrevrange('leaderboard', 0, -1, withscores=True)
print(f"Players (desc): {players_desc}")

# 获取排名
rank = r.zrevrank('leaderboard', 'player1')  # 从高到低排名
print(f"Player1 rank: {rank}")

# 按分数范围获取元素
high_scores = r.zrangebyscore('leaderboard', 1000, 2000, withscores=True)
print(f"High scores: {high_scores}")

# 增加元素分数
r.zincrby('leaderboard', 500, 'player1')
new_score = r.zscore('leaderboard', 'player1')
print(f"Player1 new score: {new_score}")

数据类型操作

发布订阅

python 复制代码
import redis
import threading
import time

def publisher():
    """发布者"""
    r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    for i in range(5):
        message = f"Message {i+1}"
        r.publish('channel', message)
        print(f"Published: {message}")
        time.sleep(1)

def subscriber():
    """订阅者"""
    r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    pubsub = r.pubsub()
    pubsub.subscribe('channel')
    
    print("等待消息...")
    for message in pubsub.listen():
        if message['type'] == 'message':
            print(f"Received: {message['data']}")

# 在单独的线程中运行订阅者
sub_thread = threading.Thread(target=subscriber)
sub_thread.daemon = True
sub_thread.start()

# 给订阅者一些时间连接
time.sleep(1)

# 运行发布者
publisher()

事务操作

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 使用管道(事务)
def transfer_funds(from_user, to_user, amount):
    """转账函数"""
    pipe = r.pipeline()
    
    try:
        # 监视相关键
        pipe.watch(f'balance:{from_user}', f'balance:{to_user}')
        
        # 检查余额
        from_balance = int(pipe.get(f'balance:{from_user}') or 0)
        if from_balance < amount:
            print("余额不足")
            return False
        
        # 开始事务
        pipe.multi()
        pipe.decrby(f'balance:{from_user}', amount)
        pipe.incrby(f'balance:{to_user}', amount)
        
        # 执行事务
        pipe.execute()
        print("转账成功")
        return True
        
    except redis.WatchError:
        print("数据已被修改,转账失败")
        return False
    finally:
        pipe.reset()

# 初始化余额
r.set('balance:user1', 1000)
r.set('balance:user2', 500)

# 执行转账
transfer_funds('user1', 'user2', 200)

# 检查余额
print(f"User1 balance: {r.get('balance:user1')}")
print(f"User2 balance: {r.get('balance:user2')}")

键过期和生存时间

python 复制代码
import redis
import time

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 设置键并指定过期时间
r.setex('session:user123', 30, 'user_data')  # 30秒后过期

# 设置过期时间
r.expire('session:user123', 60)  # 重新设置为60秒

# 获取剩余生存时间
ttl = r.ttl('session:user123')
print(f"剩余生存时间: {ttl} 秒")

# 持久化键(移除过期时间)
r.persist('session:user123')

# 使用 SET 命令的过期选项
r.set('temp_data', 'some_value', ex=10)  # 10秒后过期

高级功能

Lua 脚本

python 复制代码
import redis

r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

# 定义 Lua 脚本
lua_script = """
local current = redis.call('GET', KEYS[1])
if current then
    current = tonumber(current)
    if current >= tonumber(ARGV[1]) then
        redis.call('DECRBY', KEYS[1], ARGV[1])
        return true
    else
        return false
    end
else
    return false
end
"""

# 注册脚本
deduct_script = r.register_script(lua_script)

# 使用脚本
r.set('inventory:item1', 100)
result = deduct_script(keys=['inventory:item1'], args=[10])
print(f"扣除结果: {result}")
print(f"剩余库存: {r.get('inventory:item1')}")

连接 Redis 集群

python 复制代码
from rediscluster import RedisCluster

# Redis 集群节点
startup_nodes = [
    {"host": "127.0.0.1", "port": "7000"},
    {"host": "127.0.0.1", "port": "7001"},
    {"host": "127.0.0.1", "port": "7002"},
]

# 创建集群客户端
rc = RedisCluster(
    startup_nodes=startup_nodes, 
    decode_responses=True
)

# 使用集群
rc.set("key", "value")
print(rc.get("key"))

最佳实践

1. 错误处理

python 复制代码
import redis
from redis.exceptions import ConnectionError, TimeoutError

def safe_redis_operation():
    try:
        r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
        r.ping()
        
        # 执行 Redis 操作
        r.set('key', 'value')
        result = r.get('key')
        return result
        
    except ConnectionError:
        print("无法连接到 Redis")
        return None
    except TimeoutError:
        print("Redis 操作超时")
        return None
    except Exception as e:
        print(f"Redis 操作错误: {e}")
        return None

2. 使用连接池

python 复制代码
import redis

class RedisManager:
    def __init__(self, host='localhost', port=6379, db=0, max_connections=10):
        self.pool = redis.ConnectionPool(
            host=host,
            port=port,
            db=db,
            decode_responses=True,
            max_connections=max_connections
        )
    
    def get_connection(self):
        return redis.Redis(connection_pool=self.pool)

# 使用 RedisManager
redis_manager = RedisManager()
r = redis_manager.get_connection()
r.set('key', 'value')

3. 配置管理

python 复制代码
import redis
import json

class ConfigManager:
    def __init__(self, redis_client, prefix='config:'):
        self.redis = redis_client
        self.prefix = prefix
    
    def set_config(self, key, value):
        """设置配置"""
        if isinstance(value, (dict, list)):
            value = json.dumps(value)
        self.redis.set(f"{self.prefix}{key}", value)
    
    def get_config(self, key, default=None):
        """获取配置"""
        value = self.redis.get(f"{self.prefix}{key}")
        if value is None:
            return default
        
        # 尝试解析 JSON
        try:
            return json.loads(value)
        except json.JSONDecodeError:
            return value

# 使用配置管理器
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
config_manager = ConfigManager(r)

# 设置配置
config_manager.set_config('app_name', 'MyApp')
config_manager.set_config('settings', {'debug': True, 'max_users': 100})

# 获取配置
app_name = config_manager.get_config('app_name')
settings = config_manager.get_config('settings')
print(f"App: {app_name}, Settings: {settings}")

完整示例

下面是一个完整的 Redis 缓存示例:

python 复制代码
import redis
import time
import json
from functools import wraps

class RedisCache:
    def __init__(self, host='localhost', port=6379, db=0, default_timeout=300):
        self.redis = redis.Redis(
            host=host,
            port=port,
            db=db,
            decode_responses=True
        )
        self.default_timeout = default_timeout
    
    def set(self, key, value, timeout=None):
        """设置缓存"""
        if timeout is None:
            timeout = self.default_timeout
        
        if isinstance(value, (dict, list)):
            value = json.dumps(value)
        
        self.redis.setex(key, timeout, value)
    
    def get(self, key, default=None):
        """获取缓存"""
        value = self.redis.get(key)
        if value is None:
            return default
        
        # 尝试解析 JSON
        try:
            return json.loads(value)
        except json.JSONDecodeError:
            return value
    
    def delete(self, key):
        """删除缓存"""
        self.redis.delete(key)
    
    def clear(self):
        """清空所有缓存"""
        self.redis.flushdb()
    
    def cache(self, timeout=None, key_prefix='cache:'):
        """缓存装饰器"""
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                # 生成缓存键
                cache_key = f"{key_prefix}{func.__name__}:{str(args)}:{str(kwargs)}"
                
                # 尝试从缓存获取
                cached_result = self.get(cache_key)
                if cached_result is not None:
                    print(f"从缓存获取: {cache_key}")
                    return cached_result
                
                # 执行函数
                result = func(*args, **kwargs)
                
                # 缓存结果
                self.set(cache_key, result, timeout)
                print(f"设置缓存: {cache_key}")
                
                return result
            return wrapper
        return decorator

# 使用示例
cache = RedisCache()

@cache.cache(timeout=60)  # 缓存60秒
def expensive_operation(n):
    """模拟耗时操作"""
    print(f"执行耗时操作: {n}")
    time.sleep(2)  # 模拟耗时
    return n * n

# 测试
if __name__ == "__main__":
    # 第一次调用会执行函数并缓存结果
    result1 = expensive_operation(5)
    print(f"结果: {result1}")
    
    # 第二次调用会从缓存获取
    result2 = expensive_operation(5)
    print(f"结果: {result2}")
    
    # 不同的参数会创建不同的缓存
    result3 = expensive_operation(10)
    print(f"结果: {result3}")

本文章涵盖了 Python 使用 Redis 的主要方面,包括基本操作、数据类型、高级功能和最佳实践。根据你的具体需求,可以选择适合的功能来使用。

相关推荐
小小毛毛虫~2 小时前
使用Cursor遇到的问题(一):cursor使用conda虚拟环境
python·conda·cursor
Savvy..2 小时前
Redis 黑马点评-商户查询缓存
数据库·redis·缓存
livingbody3 小时前
【2025年9月版 亲测可用】《人民日报》PDF文件下载
开发语言·爬虫·python·pdf
合作小小程序员小小店4 小时前
web网页开发,在线%推荐算法学院培养计划,图书推荐,基于Python,FlaskWeb,用户和物品推荐MySql
python·mysql·算法·flask·推荐算法
不要再敲了4 小时前
SSM框架下的redis使用以及token认证
数据库·spring boot·redis·缓存·mybatis
那我掉的头发算什么4 小时前
【数据结构】二叉树的高频热门面试题大全
java·开发语言·数据结构·python·算法·链表·intellij idea
飞翔的佩奇5 小时前
【完整源码+数据集+部署教程】 小麦病害分割系统: yolov8-seg-dyhead
python·yolo·计算机视觉·数据集·yolov8·小麦病害分割系统
小蕾Java5 小时前
PyCharm2025.2 大更新,AI是亮点!
人工智能·python
忆~遂愿6 小时前
谷歌云+Apache Airflow,数据处理自动化的强力武器
人工智能·python·深度学习·opencv·自动化·apache