目录
[一、 Redis 简介](#一、 Redis 简介)
[2.基本键 (Key) 操作](#2.基本键 (Key) 操作)
[1. 字符串 (String)](#1. 字符串 (String))
[2. 哈希 (Hash)](#2. 哈希 (Hash))
[3. 列表 (List)](#3. 列表 (List))
[4. 集合 (Set)](#4. 集合 (Set))
[5. 有序集合 (Sorted Set / ZSet)](#5. 有序集合 (Sorted Set / ZSet))
一、 Redis 简介
Redis (Remote Dictionary Server) 是一个开源的、基于内存的键值存储系统。它通常被用作数据库、缓存和消息代理。支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。
主要特性:
-
内存存储:数据主要存储在内存中,读写速度极快。
-
数据结构丰富:不仅仅是简单的字符串,支持复杂的数据结构。
-
持久化:支持 RDB(快照)和 AOF(追加日志)两种方式将数据持久化到磁盘。
-
高可用和分布式:通过 Redis Sentinel 实现高可用,通过 Redis Cluster 实现自动分片。
-
发布/订阅:支持消息的发布和订阅模式。
二、基础操作与连接
1.建立连接
python
import redis
# 连接到本地默认端口 (6379) 的 Redis
r = redis.Redis(host='localhost', port=6379, db=0, password=None)
# 测试连接
print(r.ping()) # 输出 True 表示成功
2.基本键 (Key) 操作
python
# 设置键值对
r.set('name', 'Alice')
# 获取值
name = r.get('name') # 返回 bytes 类型, b'Alice'
name_str = r.get('name').decode('utf-8') # 解码为字符串 'Alice'
# 设置过期时间 (单位:秒)
r.setex('temp_data', 300, 'This will expire in 5 minutes')
# 检查键是否存在
exists = r.exists('name')
# 删除键
r.delete('name')
# 查找所有匹配模式的键 (谨慎在生产环境使用,可能阻塞)
keys = r.keys('user:*') # 查找所有以 'user:' 开头的键
三、数据结构操作
1. 字符串 (String)
最基础的数据类型。
python
r.set('counter', 100)
r.incr('counter') # 101, 原子性增加 1
r.decr('counter') # 100, 原子性减少 1
r.incrby('counter', 50) # 150, 原子性增加 50
r.mset({'key1': 'value1', 'key2': 'value2'}) # 设置多个键值对
values = r.mget('key1', 'key2') # 获取多个值
2. 哈希 (Hash)
适合存储对象。
python
# 模拟一个用户对象
user_id = 1000
r.hset(f'user:{user_id}', 'name', 'Bob')
r.hset(f'user:{user_id}', 'email', 'bob@example.com')
r.hset(f'user:{user_id}', 'age', 25)
# 一次性设置多个字段
r.hmset(f'user:{user_id}', {'name': 'Bob', 'email': 'bob@example.com'})
# 获取单个字段
name = r.hget(f'user:{user_id}', 'name')
# 获取所有字段和值
user_data = r.hgetall(f'user:{user_id}') # 返回字典 {b'name': b'Bob', ...}
# 增加字段的值
r.hincrby(f'user:{user_id}', 'age', 1) # age 变为 26
3. 列表 (List)
简单的字符串列表,按插入顺序排序,可实现栈或队列。
python
key = 'tasks'
r.rpush(key, 'task1') # 从右边插入 ['task1']
r.rpush(key, 'task2') # ['task1', 'task2']
r.lpush(key, 'high_priority_task') # ['high_priority_task', 'task1', 'task2']
task = r.lpop(key) # 从左边弹出一个元素 'high_priority_task'
task = r.rpop(key) # 从右边弹出一个元素 'task2'
# 获取列表片段
all_tasks = r.lrange(key, 0, -1) # 获取所有元素
first_two = r.lrange(key, 0, 1) # 获取前两个元素
4. 集合 (Set)
无序且元素唯一的集合,适合去重和关系运算。
python
key = 'tags'
r.sadd(key, 'python', 'redis', 'database') # 添加元素
r.sadd(key, 'python') # 添加重复元素,无效
members = r.smembers(key) # 获取所有成员(无序)
is_member = r.sismember(key, 'python') # 检查是否是成员
# 集合运算
r.sadd('set1', 'a', 'b', 'c')
r.sadd('set2', 'c', 'd', 'e')
inter = r.sinter('set1', 'set2') # 交集 {b'c'}
union = r.sunion('set1', 'set2') # 并集 {b'a', b'b', ...}
diff = r.sdiff('set1', 'set2') # 差集 (在 set1 但不在 set2) {b'a', b'b'}
5. 有序集合 (Sorted Set / ZSet)
每个成员都关联一个分数 (score),按分数排序,适合排行榜、优先级队列。
python
key = 'leaderboard'
r.zadd(key, {'Alice': 100, 'Bob': 85, 'Charlie': 95}) # 添加成员和分数
# 获取排名 (从高到低,分数大的在前面)
top_players = r.zrevrange(key, 0, 2, withscores=True) # 前3名,带分数
# [(b'Alice', 100.0), (b'Charlie', 95.0), (b'Bob', 85.0)]
# 获取某个成员的排名 (从0开始)
alice_rank = r.zrevrank(key, 'Alice') # 0, 第一名
# 增加某个成员的分数
r.zincrby(key, 10, 'Bob') # Bob 的分数增加 10,变为 95
四、redis缓存mysql数据
1.原因分析
MySQL 是一个关系型数据库,数据存储在硬盘上,适合持久化存储和复杂查询。但当访问量巨大时,直接频繁读写 MySQL 会成为系统瓶颈,导致响应变慢。
Redis 是一个内存键值数据库 ,数据主要存储在内存中,读写速度极快(可达 10万+/次 QPS)。它的作用是作为 MySQL 的"前锋",挡住绝大部分的读请求。
2.python操作案例
(1)首先安装所需的库:
python
pip install redis pymysql
(2)mysql表结构
sql
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
(3)代码实现
python
import json
import pymysql
import redis
from typing import Optional, Dict, Any
# 1. 初始化连接
# MySQL 连接配置
mysql_config = {
'host': 'localhost',
'user': 'your_username',
'password': 'your_password',
'database': 'your_database',
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor # 返回字典形式的结果
}
# Redis 连接配置
redis_client = redis.Redis(
host='localhost',
port=6379,
db=0, # 默认使用 0 号数据库
password='your_redis_password', # 如果设置了密码
decode_responses=True # 将返回的 bytes 自动解码为 str
)
# 2. 定义核心函数
def get_user_from_db(user_id: int) -> Optional[Dict[str, Any]]:
"""从 MySQL 数据库获取用户信息"""
connection = pymysql.connect(**mysql_config)
try:
with connection.cursor() as cursor:
sql = "SELECT `id`, `name`, `email` FROM `users` WHERE `id` = %s"
cursor.execute(sql, (user_id,))
result = cursor.fetchone()
return result
finally:
connection.close()
def get_user(user_id: int) -> Optional[Dict[str, Any]]:
"""获取用户信息(核心缓存逻辑)"""
# 生成 Redis 中使用的 key
redis_key = f"user:{user_id}"
# 第一步:尝试从缓存中获取
user_data = redis_client.get(redis_key)
# 第二步:缓存命中
if user_data is not None:
print(f"Cache HIT for user {user_id}")
# 我们将数据存为 JSON 字符串,所以需要解析
return json.loads(user_data)
# 第三步:缓存未命中,从数据库获取
print(f"Cache MISS for user {user_id}")
user_data = get_user_from_db(user_id)
# 如果数据库中也不存在此用户,返回 None
if user_data is None:
return None
# 第四步:将数据库结果写入缓存,设置过期时间(例如 300 秒)
# 使用 json.dumps 将字典转换为 JSON 字符串存储
redis_client.setex(redis_key, 300, json.dumps(user_data))
return user_data
def update_user(user_id: int, name: str, email: str):
"""更新用户信息(处理缓存失效)"""
connection = pymysql.connect(**mysql_config)
try:
with connection.cursor() as cursor:
sql = "UPDATE `users` SET `name` = %s, `email` = %s WHERE `id` = %s"
cursor.execute(sql, (name, email, user_id))
connection.commit()
print(f"Database updated for user {user_id}")
finally:
connection.close()
# 关键步骤:使缓存失效
# 直接删除该 key 对应的缓存数据,下次读取时会自动从数据库加载最新数据
redis_key = f"user:{user_id}"
redis_client.delete(redis_key)
print(f"Cache invalidated for key {redis_key}")
# 3. 测试代码
if __name__ == "__main__":
# 测试读取
print("--- First read (should be a MISS) ---")
user1 = get_user(1)
print(user1)
print("\n--- Second read (should be a HIT) ---")
user1_again = get_user(1)
print(user1_again)
# 测试更新和缓存失效
print("\n--- Updating user ---")
update_user(1, "New Name", "new_email@example.com")
print("\n--- Read after update (should be a MISS again) ---")
user1_updated = get_user(1)
print(user1_updated) # 这里会显示新的名字和邮箱
3.缓存雪崩与缓存穿透
缓存雪崩:大量缓存数据在同一时间过期或服务宕机,导致所有请求直接访问数据库,造成数据库压力过大甚至崩溃。
缓存穿透:多次查询不存在的数据,导致每次请求都直接访问数据库。
总结
Redis 是一个高性能的内存键值数据库,常用于缓存、消息队列等场景。通过 Python 的 `redis` 库可以方便地连接和操作 Redis,支持字符串、哈希、列表、集合和有序集合等多种数据结构,能够灵活存储和高效查询数据。
在实际应用中,Redis 常被用作 MySQL 的缓存层,提升系统性能。核心流程遵循 Cache-Aside 模式:读取时先查 Redis,若未命中则从 MySQL 获取并写入 Redis;写入时先更新 MySQL,再删除 Redis 中对应缓存,保证数据一致性。
使用时需注意缓存雪崩和缓存穿透问题。雪崩指大量缓存同时失效,请求直接冲击数据库,可通过设置随机过期时间避免;穿透指查询不存在的数据,每次绕过缓存,可通过缓存空值并设置短过期时间来缓解。合理使用 Redis 能够显著减轻数据库压力,提高响应速度。