文章目录
-
- [Redis 简介](#Redis 简介)
- [安装 Redis 和 Python 客户端](#安装 Redis 和 Python 客户端)
-
- [安装 Redis 服务器](#安装 Redis 服务器)
- [安装 Python Redis 客户端](#安装 Python Redis 客户端)
- [连接 Redis](#连接 Redis)
- 基本操作
- 数据类型操作
- 高级功能
-
- [Lua 脚本](#Lua 脚本)
- [连接 Redis 集群](#连接 Redis 集群)
- 最佳实践
-
- [1. 错误处理](#1. 错误处理)
- [2. 使用连接池](#2. 使用连接池)
- [3. 配置管理](#3. 配置管理)
- 完整示例
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 的主要方面,包括基本操作、数据类型、高级功能和最佳实践。根据你的具体需求,可以选择适合的功能来使用。