Python 读写 Redis 缓存数据库:写给 Python 初学者的入门案例

Python 读写 Redis 缓存数据库:写给 Python 初学者的入门案例

很多学习 Python 的小伙伴,在学完文件读写、SQLite、MySQL 之后,都会接触到一个新的数据库:Redis。

Redis 和传统关系型数据库不太一样。MySQL、SQLite 更擅长长期保存结构化数据,而 Redis 更常用于缓存、计数器、排行榜、验证码、分布式锁、消息队列等高性能场景。

这篇文章会先简单介绍 Redis 是什么,然后通过 Python 代码演示如何连接 Redis,并完成常见的读写操作。

一、Redis 是什么

Redis 全称是 Remote Dictionary Server,可以理解为一个高性能的内存型 Key-Value 数据库。

它的核心特点是:

  1. 数据主要存放在内存中,读写速度非常快
  2. 使用 Key-Value 形式保存数据
  3. 支持丰富的数据结构,不只是简单字符串
  4. 支持设置过期时间,适合做缓存
  5. 支持持久化,可以把内存数据保存到磁盘
  6. 常用于缓存、计数、排行榜、会话、限流等场景

我们可以把 Redis 想象成一个超快的字典:

python 复制代码
cache = {
    "user:1:name": "Alice",
    "article:100:view_count": 358,
    "login:code:13800138000": "829316"
}

只不过这个字典不是保存在 Python 程序里,而是保存在 Redis 服务中。多个程序、多个接口、多个服务器都可以一起访问它。

二、Redis 和 MySQL、SQLite 有什么区别

简单对比一下:

对比项 Redis MySQL / SQLite
存储方式 主要在内存中 主要在磁盘中
数据模型 Key-Value 和多种数据结构 表、行、列
读写速度 非常快 相对较慢
常见用途 缓存、计数、排行榜、验证码 业务数据持久化
查询方式 通过 key 访问 SQL 查询
是否适合复杂查询 不适合 适合

所以 Redis 通常不是用来完全替代 MySQL 或 SQLite 的,而是和它们配合使用。

例如:

  1. 用户资料保存在 MySQL 中
  2. 热门用户资料缓存到 Redis 中
  3. 下次查询时先查 Redis
  4. Redis 没有命中,再查 MySQL
  5. 查到后再写回 Redis

这个模式通常叫缓存旁路,也叫 Cache Aside。

三、准备 Redis 环境

如果你本机已经安装 Redis,可以直接启动 Redis 服务。

如果没有安装,也可以使用 Docker 快速启动:

bash 复制代码
docker run --name redis-demo -p 6379:6379 -d redis

测试 Redis 是否可用:

bash 复制代码
redis-cli ping

如果返回:

bash 复制代码
PONG

说明 Redis 服务已经启动成功。

四、安装 Python Redis 客户端

Python 操作 Redis 常用的库是 redis

安装命令:

bash 复制代码
pip install redis

安装完成后,可以在 Python 中导入:

python 复制代码
import redis

五、连接 Redis

新建一个文件 redis_demo.py

python 复制代码
import redis


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

print(r.ping())

运行:

bash 复制代码
python redis_demo.py

如果输出:

bash 复制代码
True

说明 Python 已经成功连接到 Redis。

这里的几个参数含义如下:

参数 说明
host Redis 服务器地址
port Redis 端口,默认 6379
db Redis 数据库编号,默认 0
decode_responses 是否把返回值自动解码成字符串

如果不设置 decode_responses=True,Redis 返回的字符串可能是字节类型:

python 复制代码
b'Alice'

对初学者来说,建议先加上 decode_responses=True,这样输出更直观。

六、字符串 String:最基础的缓存读写

Redis 最简单的数据类型是 String。

可以用它保存用户名、验证码、Token、简单配置、缓存结果等。

python 复制代码
import redis


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

# 写入字符串
r.set("user:1:name", "Alice")

# 读取字符串
name = r.get("user:1:name")
print(name)

输出:

bash 复制代码
Alice

设置过期时间

缓存通常不应该永久存在,所以 Redis 支持给 key 设置过期时间。

例如保存短信验证码,60 秒后自动删除:

python 复制代码
r.set("login:code:13800138000", "829316", ex=60)

code = r.get("login:code:13800138000")
print(code)

其中 ex=60 表示 60 秒后过期。

也可以先写入,再单独设置过期时间:

python 复制代码
r.set("temp:data", "hello")
r.expire("temp:data", 30)

查看剩余过期时间:

python 复制代码
ttl = r.ttl("temp:data")
print(ttl)

七、数字自增:计数器案例

Redis 很适合做计数器,例如文章阅读量、点赞数、接口访问次数。

python 复制代码
article_key = "article:100:view_count"

r.set(article_key, 0)

r.incr(article_key)
r.incr(article_key)
r.incr(article_key)

count = r.get(article_key)
print(count)

输出:

bash 复制代码
3

也可以一次增加指定数量:

python 复制代码
r.incrby(article_key, 10)
print(r.get(article_key))

对应减少:

python 复制代码
r.decr(article_key)
r.decrby(article_key, 5)

计数器是 Redis 非常常见的使用场景,因为这类操作简单、高频,而且对速度要求高。

八、Hash:保存对象信息

如果要保存一个用户对象,用多个 String 也可以:

text 复制代码
user:1:name
user:1:age
user:1:city

但更推荐使用 Hash:

python 复制代码
r.hset("user:1", mapping={
    "name": "Alice",
    "age": 20,
    "city": "Shanghai"
})

name = r.hget("user:1", "name")
print(name)

user = r.hgetall("user:1")
print(user)

输出:

bash 复制代码
Alice
{'name': 'Alice', 'age': '20', 'city': 'Shanghai'}

修改 Hash 中的某个字段:

python 复制代码
r.hset("user:1", "city", "Beijing")

删除某个字段:

python 复制代码
r.hdel("user:1", "age")

判断字段是否存在:

python 复制代码
exists = r.hexists("user:1", "name")
print(exists)

Hash 非常适合保存用户资料、商品摘要、文章基础信息等对象型数据。

九、List:保存列表数据

Redis 的 List 可以理解为一个有序列表。

常见用途:

  1. 最新消息列表
  2. 简单队列
  3. 最近浏览记录
  4. 日志缓冲

示例:

python 复制代码
key = "user:1:recent_articles"

r.delete(key)

r.lpush(key, "article:100")
r.lpush(key, "article:101")
r.lpush(key, "article:102")

articles = r.lrange(key, 0, -1)
print(articles)

输出:

bash 复制代码
['article:102', 'article:101', 'article:100']

lpush 是从左侧插入,所以最后插入的元素排在最前面。

如果想从右侧插入,可以使用:

python 复制代码
r.rpush(key, "article:103")

从列表中弹出一个元素:

python 复制代码
item = r.lpop(key)
print(item)

限制列表长度,只保留最近 3 条:

python 复制代码
r.ltrim(key, 0, 2)

这个操作很适合做"最近浏览记录"。

十、Set:保存不重复集合

Set 是无序且不重复的集合。

常见用途:

  1. 用户标签
  2. 点赞用户集合
  3. 已签到用户集合
  4. 去重统计

示例:记录给文章点赞的用户。

python 复制代码
key = "article:100:liked_users"

r.delete(key)

r.sadd(key, "user:1")
r.sadd(key, "user:2")
r.sadd(key, "user:1")

users = r.smembers(key)
print(users)

is_liked = r.sismember(key, "user:1")
print(is_liked)

输出:

bash 复制代码
{'user:1', 'user:2'}
True

虽然添加了两次 user:1,但 Set 会自动去重。

统计集合元素数量:

python 复制代码
count = r.scard(key)
print(count)

取消点赞:

python 复制代码
r.srem(key, "user:1")

十一、Sorted Set:排行榜案例

Sorted Set 是有序集合,每个元素都有一个分数。

它非常适合做排行榜。

例如游戏积分排行榜:

python 复制代码
key = "game:rank"

r.delete(key)

r.zadd(key, {
    "Alice": 1500,
    "Bob": 1800,
    "Cindy": 1700,
    "David": 1200
})

top3 = r.zrevrange(key, 0, 2, withscores=True)
print(top3)

输出:

bash 复制代码
[('Bob', 1800.0), ('Cindy', 1700.0), ('Alice', 1500.0)]

给用户增加积分:

python 复制代码
r.zincrby(key, 200, "Alice")

查询 Alice 的排名:

python 复制代码
rank = r.zrevrank(key, "Alice")
print(rank)

注意:Redis 的排名从 0 开始。如果返回 0,表示第一名。

十二、保存 JSON 数据

有时我们希望把一个 Python 字典直接缓存起来。

可以使用 json.dumps() 转成字符串保存,读取时再用 json.loads() 转回来。

python 复制代码
import json
import redis


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

user = {
    "id": 1,
    "name": "Alice",
    "age": 20,
    "roles": ["admin", "editor"]
}

r.set("cache:user:1", json.dumps(user, ensure_ascii=False), ex=300)

cached_text = r.get("cache:user:1")
cached_user = json.loads(cached_text)

print(cached_user["name"])
print(cached_user["roles"])

这种方式很适合缓存接口返回结果。

不过要注意:Redis 本身保存的是字符串。如果你要频繁修改对象中的某个字段,Hash 可能比 JSON 字符串更方便。

十三、完整案例:使用 Redis 缓存用户资料

下面做一个更贴近实际项目的案例。

假设我们有一个"慢查询函数",它模拟从数据库查询用户资料。为了提高速度,我们先查 Redis;如果 Redis 中没有,再查数据库,并把结果写入 Redis。

python 复制代码
import json
import time
import redis


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


def query_user_from_database(user_id):
    """模拟数据库查询。"""
    print("正在查询数据库...")
    time.sleep(2)

    fake_database = {
        1: {"id": 1, "name": "Alice", "age": 20},
        2: {"id": 2, "name": "Bob", "age": 22},
        3: {"id": 3, "name": "Cindy", "age": 19},
    }
    return fake_database.get(user_id)


def get_user(user_id):
    """优先从 Redis 缓存读取用户资料。"""
    cache_key = f"cache:user:{user_id}"

    cached_user = r.get(cache_key)
    if cached_user:
        print("命中 Redis 缓存")
        return json.loads(cached_user)

    user = query_user_from_database(user_id)
    if user is None:
        return None

    r.set(cache_key, json.dumps(user, ensure_ascii=False), ex=60)
    print("已写入 Redis 缓存")
    return user


if __name__ == "__main__":
    print(get_user(1))
    print(get_user(1))

第一次运行时,输出类似:

bash 复制代码
正在查询数据库...
已写入 Redis 缓存
{'id': 1, 'name': 'Alice', 'age': 20}
命中 Redis 缓存
{'id': 1, 'name': 'Alice', 'age': 20}

第一次查询 Redis 没有数据,所以会访问"数据库",并等待 2 秒。

第二次查询时,Redis 中已经有缓存,所以直接返回,速度明显更快。

这就是 Redis 最典型的缓存使用方式。

十四、封装一个简单的 Redis 工具类

在项目中,我们通常不会把 Redis 操作散落在各个地方。可以先封装一个简单工具类:

python 复制代码
import json
import redis


class RedisCache:
    def __init__(self, host="localhost", port=6379, db=0):
        self.client = redis.Redis(
            host=host,
            port=port,
            db=db,
            decode_responses=True
        )

    def set_json(self, key, value, expire_seconds=300):
        text = json.dumps(value, ensure_ascii=False)
        self.client.set(key, text, ex=expire_seconds)

    def get_json(self, key):
        text = self.client.get(key)
        if text is None:
            return None
        return json.loads(text)

    def delete(self, key):
        return self.client.delete(key)

    def exists(self, key):
        return self.client.exists(key) == 1


cache = RedisCache()

cache.set_json("user:1", {"id": 1, "name": "Alice"}, expire_seconds=60)

user = cache.get_json("user:1")
print(user)

print(cache.exists("user:1"))

cache.delete("user:1")

这样后续业务代码会更清晰。

十五、连接池:更适合项目使用

在 Web 项目中,不建议每次请求都重新创建 Redis 连接。

可以使用连接池:

python 复制代码
import redis


pool = redis.ConnectionPool(
    host="localhost",
    port=6379,
    db=0,
    decode_responses=True,
    max_connections=20
)

r = redis.Redis(connection_pool=pool)

r.set("site:name", "Python Redis Demo")
print(r.get("site:name"))

连接池可以复用连接,减少频繁创建连接带来的开销。

如果你以后使用 Flask、FastAPI、Django,也可以在应用启动时创建 Redis 客户端,然后在接口中复用它。

十六、删除 key 和清理数据库

删除一个 key:

python 复制代码
r.delete("user:1")

判断 key 是否存在:

python 复制代码
exists = r.exists("user:1")
print(exists)

查看匹配的 key:

python 复制代码
keys = r.keys("user:*")
print(keys)

清空当前数据库:

python 复制代码
r.flushdb()

清空所有数据库:

python 复制代码
r.flushall()

注意:flushdb()flushall() 都是危险操作,真实项目中不要随便执行。

十七、初学者常见问题

1. 连接失败

常见错误:

bash 复制代码
redis.exceptions.ConnectionError

可能原因:

  1. Redis 服务没有启动
  2. host 或 port 写错了
  3. Docker 容器没有映射 6379 端口
  4. Redis 设置了密码,但代码中没有配置

如果 Redis 设置了密码,需要这样连接:

python 复制代码
r = redis.Redis(
    host="localhost",
    port=6379,
    password="your_password",
    decode_responses=True
)

2. 读取结果是字节类型

如果看到:

python 复制代码
b'Alice'

可以在连接时加上:

python 复制代码
decode_responses=True

3. JSON 读取报错

如果执行:

python 复制代码
json.loads(text)

报错,通常说明 Redis 中保存的内容不是合法 JSON 字符串。

建议保存和读取都封装成统一方法,避免同一个 key 有时存普通字符串,有时存 JSON。

4. 缓存数据不是最新的

缓存会带来一个新问题:数据库更新了,但 Redis 里还是旧数据。

常见处理方式:

  1. 更新数据库后删除缓存
  2. 设置较短的过期时间
  3. 对一致性要求很高的数据,不要随便缓存

例如:

python 复制代码
def update_user_name(user_id, new_name):
    update_database_user_name(user_id, new_name)
    r.delete(f"cache:user:{user_id}")

这样下次查询时会重新从数据库读取最新数据,再写入 Redis。

十八、Redis key 命名建议

Redis 的 key 最好有清晰的命名规则。

推荐格式:

text 复制代码
业务名:对象名:对象ID:字段名

例如:

text 复制代码
user:1:profile
user:1:recent_articles
article:100:view_count
article:100:liked_users
login:code:13800138000
game:rank

好的 key 命名可以让排查问题更容易。

不推荐随意命名:

text 复制代码
a
test
data1
abc

项目变大后,这类 key 很难维护。

十九、什么时候适合使用 Redis

适合使用 Redis 的场景:

  1. 高频读取的数据
  2. 可以设置过期时间的数据
  3. 允许短时间不一致的数据
  4. 计数器、排行榜、点赞集合
  5. 验证码、Token、Session
  6. 接口限流、简单队列

不适合使用 Redis 的场景:

  1. 复杂 SQL 查询
  2. 强事务业务
  3. 长期保存的核心数据
  4. 需要大量关联查询的数据

一句话总结:核心业务数据放 MySQL、PostgreSQL、SQLite 等数据库中,Redis 更适合放热点数据和临时数据。

二十、完整练习代码

最后给出一个可以直接运行的综合练习:

python 复制代码
import json
import redis


def main():
    r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

    print("连接状态:", r.ping())

    print("\n=== String 示例 ===")
    r.set("app:name", "Redis Python Demo", ex=300)
    print(r.get("app:name"))

    print("\n=== Counter 示例 ===")
    r.delete("article:1:view_count")
    for _ in range(5):
        r.incr("article:1:view_count")
    print(r.get("article:1:view_count"))

    print("\n=== Hash 示例 ===")
    r.hset("user:1", mapping={"name": "Alice", "age": 20, "city": "Shanghai"})
    print(r.hgetall("user:1"))

    print("\n=== List 示例 ===")
    r.delete("user:1:recent")
    r.lpush("user:1:recent", "article:100", "article:101", "article:102")
    print(r.lrange("user:1:recent", 0, -1))

    print("\n=== Set 示例 ===")
    r.delete("article:1:likes")
    r.sadd("article:1:likes", "user:1", "user:2", "user:1")
    print(r.smembers("article:1:likes"))

    print("\n=== Sorted Set 示例 ===")
    r.delete("rank:score")
    r.zadd("rank:score", {"Alice": 98, "Bob": 86, "Cindy": 95})
    print(r.zrevrange("rank:score", 0, -1, withscores=True))

    print("\n=== JSON 缓存示例 ===")
    user = {"id": 1, "name": "Alice", "skills": ["Python", "Redis"]}
    r.set("cache:user:1", json.dumps(user, ensure_ascii=False), ex=60)
    cached_user = json.loads(r.get("cache:user:1"))
    print(cached_user)


if __name__ == "__main__":
    main()

运行前确保:

  1. Redis 服务已经启动
  2. 已安装 Python 依赖:pip install redis
  3. 代码中的 host、port、password 配置正确

总结

Python 操作 Redis 的核心流程并不复杂:

text 复制代码
安装 redis 库 -> 连接 Redis -> 选择数据结构 -> 写入数据 -> 读取数据 -> 设置过期时间

常用方法可以简单记住:

方法 作用
set() / get() 读写字符串
incr() / decr() 计数器
hset() / hgetall() 操作 Hash
lpush() / lrange() 操作 List
sadd() / smembers() 操作 Set
zadd() / zrevrange() 操作排行榜
expire() / ttl() 设置和查看过期时间
delete() 删除 key

对 Python 初学者来说,学习 Redis 的重点不是一开始就背所有命令,而是先理解它适合解决什么问题。

如果你能掌握缓存用户资料、验证码、计数器、排行榜这几个案例,就已经可以在很多真实项目中使用 Redis 了。

相关推荐
m0_684501982 小时前
HTML图片怎么用Bitbucket Pipelines发布_Bitbucket自动构建HTML站点
jvm·数据库·python
小江的记录本2 小时前
【分布式】分布式核心组件——分布式限流:固定窗口、滑动窗口、漏桶、令牌桶算法,网关层/服务层限流实现
java·分布式·后端·python·算法·安全·面试
MediaTea2 小时前
Scikit-learn:特征矩阵与目标变量
人工智能·python·机器学习·矩阵·scikit-learn
不懂的浪漫2 小时前
一次设备映射缓存设计:用多索引 Map 把高频查询从遍历变成直接命中
java·算法·spring·缓存
HappyAcmen2 小时前
4.字典dict全部用法
python
好家伙VCC2 小时前
# React发散创新:从状态管理到自定义Hook的极致实践与性能优化在现代前端开发
java·javascript·python·react.js·性能优化
郝学胜-神的一滴2 小时前
深度学习入门:极简神经网络搭建与参数计算全攻略
人工智能·pytorch·python·深度学习·神经网络·机器学习
Metaphor6922 小时前
使用 Python 提取 PDF 文件中的文本、表格、图片
开发语言·python·pdf
2301_796588502 小时前
Navicat连ClickHouse出现中文乱码怎么办_字符集编码调整
jvm·数据库·python