AI大模型学习07:数据分析之Pymysql和Redis
今天的目标很实在:搞懂 Python 怎么连接 MySQL 和 Redis,弄清楚查询和修改的区别,最重要的是——彻底理解 Redis 的字符串和哈希到底有什么不同。
一、MySQL 和 Redis 分别用来干什么?
很多新手会问:有了 MySQL,为什么还要学 Redis?
-
MySQL 像你家的 大书柜:容量大,能存很多书(核心数据),但找书、放书稍微慢一点(数据在硬盘上)。
-
Redis 像你 手边的小推车:容量小,但随手拿随手放,速度飞快(数据在内存里)。
实际项目中,两者配合使用:
-
MySQL 存放不能丢的数据:用户、订单、财务流水。
-
Redis 存放高频访问的“热点副本”:商品详情缓存、验证码、登录会话、点赞数、排行榜。
一句话:MySQL 存“根本”,Redis 当“加速器”。
二、PyMySQL:Python 连 MySQL 的“翻译官”
1. 三者关系
-
MySQL:真正的数据库服务(存数据)。
-
Python:写业务逻辑的程序。
-
PyMySQL:Python 的一个第三方库,负责把 Python 的指令翻译成 MySQL 能听懂的话,再把结果翻译回来。
类比:Python 是只会中文的老板,MySQL 是只会英文的仓库管理员,PyMySQL 就是同声传译。
2. 核心流程(4 步)
import pymysql
# 1. 建立连接
conn = pymysql.connect(host='127.0.0.1', user='root', password='你的密码', database='test')
# 2. 创建游标
cursor = conn.cursor()
# 3. 执行 SQL
cursor.execute("SELECT * FROM users")
# 4. 获取结果并关闭
rows = cursor.fetchall()
cursor.close()
conn.close()
3. 查询 vs 增删改 —— 关键区别
| 操作类型 | 是否需要 commit |
如何取结果 |
|---|---|---|
| 查询 (SELECT) | 不需要 | fetchone() / fetchall() |
| 增删改 (INSERT/UPDATE/DELETE) | 必须 commit() |
用 cursor.rowcount 看影响行数 |
示例:修改数据 + 事务回滚
try:
cursor.execute("UPDATE users SET balance = balance - 100 WHERE name = '小明'")
cursor.execute("UPDATE users SET balance = balance + 100 WHERE name = '小红'")
conn.commit() # 两条都成功才提交
except:
conn.rollback() # 任何一条出错,撤销所有修改
记住口诀:查询只 fetch,修改要 commit,出错 rollback。
三、Redis 安装与连接
Redis 包含两个东西:
-
Redis 服务:真正的数据库程序(需要单独安装启动)。
-
redis-py:Python 的客户端库(
pip install redis)。
测试连接是否成功:
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
print(r.ping()) # 输出 True 表示连通
加上
decode_responses=True可以让 Redis 自动返回字符串,而不是字节。
四、Redis 的五大金刚(数据类型)
| 类型 | 一句话理解 | 典型场景 |
|---|---|---|
| String | 一个 key 对应一个值 | 缓存、计数器、验证码 |
| Hash | 一个 key 对应多个字段(像一个小字典) | 用户信息、购物车 |
| List | 有序、可重复的列表 | 消息队列、最新列表 |
| Set | 无序、不重复的集合 | 抽奖去重、共同好友 |
| Sorted Set | 带分数的有序集合 | 排行榜 |
五、重中之重:String(存 JSON) vs Hash(存对象)
这是今天最核心、最易混淆的知识点,必须彻底搞懂。
场景:存储一个用户(姓名:张三,年龄:20,城市:北京)
1. 用 String 存 JSON
SET user:1 '{"name":"张三","age":20,"city":"北京"}'
想改年龄为 21 怎么办?
你只能:取出整个字符串 → 解析 JSON → 改年龄 → 转成字符串 → 写回。
即使用代码,也要三步:
data = json.loads(r.get("user:1"))
data["age"] = 21
r.set("user:1", json.dumps(data))
问题:
-
改一个字段,却要读写整个对象,性能差、网络浪费。
-
如果两个人同时改(比如一个改年龄、一个改城市),后执行的会覆盖先执行的,数据丢失。
2. 用 Hash 存储
HSET user:1 name "张三" age 20 city "北京"
改年龄只需一行:
HSET user:1 age 21
甚至可以直接加一岁:
HINCRBY user:1 age 1
优势:
-
只操作目标字段,其他字段不动。
-
原子操作,无并发覆盖问题。
-
代码简洁,性能高。
3. 为什么 String 不能只改一部分?
因为 Redis 把 String 的值看作一个 整体黑盒,不知道里面是 JSON 还是别的格式,也没有“修改内部某个字段”的命令。
而 Hash 在设计时就把每个 field 当作独立单元,天然支持部分修改。
4. 什么时候用哪个?
| 使用场景 | 推荐类型 |
|---|---|
| 经常单独修改某个属性(积分、点赞数、状态) | Hash |
| 总是整体读写(缓存 HTML 片段、图片 base64) | String |
| 需要每个对象独立过期(Hash 只能整个 key 过期) | String |
| 小对象且字段少(内存效率高) | Hash |
一句话:Hash 就是为“频繁改对象的某几个字段”而生的,别再拿 String 存 JSON 去改字段了,那是弯路。
六、其他 Redis 类型简单示例
1. String – 计数器(文章阅读数)
r.set("article:1001:views", 0)
r.incr("article:1001:views") # 阅读 +1
r.incrby("article:1001:views", 5) # 一次加 5
2. Hash – 购物车
r.hset("cart:1001", "apple", 3)
r.hset("cart:1001", "banana", 2)
r.hincrby("cart:1001", "apple", 1) # 苹果加一个
3. List – 消息队列(先进先出)
r.lpush("tasks", "task1", "task2") # 左边加
task = r.rpop("tasks") # 右边取
4. Set – 抽奖去重
r.sadd("lottery", "张三", "李四", "张三") # 张三只加一次
r.smembers("lottery") # 查看所有参与者
5. Sorted Set – 排行榜
r.zadd("rank", {"小明": 100, "小红": 95})
r.zincrby("rank", 10, "小红") # 小红加 10 分
top = r.zrevrange("rank", 0, 2, withscores=True) # 前三名
七、重要提醒:过期时间(TTL)
缓存、验证码、会话都必须设置过期时间,否则 Redis 会被垃圾数据撑爆。
r.setex("code:13800138000", 60, "123456") # 60 秒后自动删除
r.ttl("code:13800138000") # 查看剩余生存时间
注意:只有整个 key 可以设置过期时间。Hash 内部不能单独让某个 field 过期。
八、今日小结
-
PyMySQL:查询用
fetch,修改用commit,出错rollback。 -
MySQL 存核心数据,Redis 加速热点数据。
-
String 存 JSON:改一个字段 = 重写整个对象(麻烦且不安全)。
-
Hash 存对象:改一个字段 = 只动那个字段(干净利落)。
-
缓存一定要设过期时间,否则内存会爆炸。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)