跳到主要内容
Python 全栈开发:MySQL 与 Redis 数据库集成指南 | 极客日志
Python 大前端 算法
Python 全栈开发:MySQL 与 Redis 数据库集成指南 介绍 Python 全栈开发中数据库集成的核心内容。涵盖 SQLite 零配置使用、SQL 注入防护、ORM(SQLAlchemy/SQLModel)操作、数据库连接池原理与配置、事务 ACID 特性及隔离级别、索引优化原理与执行计划分析。同时介绍 Redis 缓存应用场景及基础操作。包含用户注册登录实战、转账事务模拟、球队关联查询及 Redis 排行榜实现。强调密码加密存储、连接池复用及数据备份等最佳实践。
涅槃凤凰 发布于 2026/3/30 更新于 2026/5/22 30 浏览1. 为什么我们需要数据库?
在全栈开发里,数据库就是程序的'大脑',它负责安全、高效地存储和检索海量数据。
今天,咱们就来聊聊 Python 程序员必修的两门课:关系型数据库(MySQL/SQLite)和内存数据库(Redis) 。
2. SQL:像写英文一样操作数据
2.1 SQLite:零配置的实战神器
如果你只是想练手或者写个桌面小软件,sqlite3 是最好的选择。它不需要安装服务器,直接一个文件搞定。
import sqlite3
conn = sqlite3.connect("my_app.db" )
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE
)
""" )
cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)" , ("张三" , "[email protected] " ))
conn.commit()
conn.close()
2.2 避坑指南:SQL 注入
千万别写 cursor.execute(f"SELECT * FROM users WHERE name='{user_input}'")。
如果用户输入 ' OR '1'='1,你的数据库就被人家看光了。永远使用 ? 或 %s 占位符。
3. ORM:像操作对象一样操作数据库
老实说,天天写 SQL 挺烦的。在现代开发里,我们更喜欢用 ORM(对象关系映射) 。它能让你把数据库里的表,直接映射成 Python 里的类。
3.1 SQLAlchemy 与 SQLModel
这是目前 Python 界最流行的组合。
from sqlmodel import Field, Session, SQLModel, create_engine, select
class User (SQLModel, table=True ):
id : int | None = Field(default=None , primary_key=True )
name: str
age: int
engine = create_engine( )
SQLModel.metadata.create_all(engine)
Session(engine) session:
user1 = User(name= , age= )
session.add(user1)
session.commit()
Session(engine) session:
statement = select(User).where(User.name == )
results = session. (statement)
user results:
( )
"sqlite:///database.db"
with
as
"李四"
25
with
as
"李四"
exec
for
in
print
f"找到用户:{user.name} , 年龄:{user.age} "
建议 :用了 ORM,你就再也不用担心手抖写错 SQL 关键字了,而且代码看起来非常"Pythonic"。
4. 数据库进阶:原理与优化
4.1 数据库连接池原理 想象你在银行办业务,每次都要重新排队取号、填表、等待窗口叫号——这效率太低了。数据库连接也是同样的道理。
连接池就像银行的"VIP 通道",预先创建好一定数量的数据库连接,放在池子里备用。当程序需要操作数据库时,直接从池子里取一个连接用完归还,而不是每次都新建连接。
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
engine = create_engine(
"sqlite:///database.db" ,
pool_size=5 ,
max_overflow=10 ,
pool_timeout=30 ,
pool_recycle=3600 ,
pool_pre_ping=True
)
SessionLocal = sessionmaker(autocommit=False , autoflush=False , bind=engine)
session = SessionLocal()
try :
result = session.execute(text("SELECT 1" ))
print (result.fetchone())
finally :
session.close()
阶段 说明 初始化 应用启动时,创建 pool_size 个连接 请求连接 从池中获取可用连接 连接不足 若池已满,创建 overflow 连接(不超过 max_overflow) 连接归还 使用完毕后,连接回到池中等待复用 连接回收 超过 pool_recycle 时间的连接会被重建
一句话总结 :连接池是"以空间换时间"的经典策略,用内存资源换取连接创建的开销。
4.2 事务 ACID 特性详解 事务是数据库的基石,ACID 是衡量事务可靠性的四个标准。
特性 英文 含义 生活比喻 原子性 Atomicity 事务要么全部成功,要么全部失败 转账:扣款和加款必须同时完成 一致性 Consistency 事务前后,数据库始终处于合法状态 转账前后,两人余额总和不变 隔离性 Isolation 并发事务互不干扰 两个人同时取钱,不会取到同一张钞票 持久性 Durability 事务提交后,数据永久保存 转账成功后,即使断电也不会丢失
import sqlite3
conn = sqlite3.connect("test.db" , isolation_level=None )
conn = sqlite3.connect("test.db" , isolation_level="DEFERRED" )
conn = sqlite3.connect("test.db" , isolation_level="IMMEDIATE" )
conn = sqlite3.connect("test.db" , isolation_level="EXCLUSIVE" )
隔离级别 脏读 不可重复读 幻读 性能 READ UNCOMMITTED 可能 可能 可能 最快 READ COMMITTED 不会 可能 可能 较快 REPEATABLE READ 不会 不会 可能 中等 SERIALIZABLE 不会 不会 不会 最慢
脏读 :读到其他事务未提交的数据(可能回滚)
不可重复读 :同一事务内,两次读取同一数据结果不同
幻读 :同一事务内,两次查询返回的行数不同
一句话总结 :隔离级别越高,数据一致性越好,但并发性能越差。根据业务场景选择合适的级别。
4.3 索引原理与优化 没有索引的数据库就像没有目录的字典,查找数据只能逐页翻。
索引是一种数据结构(通常是 B+ 树),它存储了列值到行位置的映射,让查询可以跳过大部分数据直接定位。
[50]
/ \
[20, 30] [70, 90]
/ | \ / | \
[10] [25] [40] [60] [80] [100]
叶子节点存储实际数据地址
索引类型 适用场景 示例 主键索引 唯一标识每行数据 PRIMARY KEY (id) 唯一索引 确保列值不重复 UNIQUE (email) 普通索引 加速查询 INDEX (name) 组合索引 多列联合查询 INDEX (name, age) 全文索引 文本搜索 FULLTEXT (content)
import sqlite3
conn = sqlite3.connect("test.db" )
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
email TEXT UNIQUE,
age INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""" )
cursor.execute("CREATE INDEX IF NOT EXISTS idx_age ON users(age)" )
cursor.execute("CREATE INDEX IF NOT EXISTS idx_name_age ON users(username, age)" )
conn.commit()
conn.close()
WHERE 子句中的列 应该建索引
最左前缀原则 :组合索引 (a, b, c) 可以支持查询 a、ab、abc,但不支持 b、bc
避免过度索引 :每个索引都会增加写入开销
选择性高的列 更适合建索引(如身份证号 > 性别)
EXPLAIN QUERY PLAN SELECT * FROM users WHERE age > 20
一句话总结 :索引是查询的加速器,但也是写入的减速带。只在必要的列上建索引,定期清理无用索引。
4.4 SQL 执行计划基础 执行计划是数据库优化器的"作战地图",它展示了 SQL 语句的执行步骤和成本估算。
import sqlite3
conn = sqlite3.connect(":memory:" )
cursor = conn.cursor()
cursor.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)" )
cursor.execute("CREATE INDEX idx_age ON users(age)" )
cursor.executemany("INSERT INTO users (name, age) VALUES (?, ?)" , [
("Alice" , 25 ),
("Bob" , 30 ),
("Charlie" , 35 )
])
print ("--- 全表扫描 ---" )
cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM users" )
for row in cursor.fetchall():
print (row)
print ("\n--- 使用索引扫描 ---" )
cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM users WHERE age > 25" )
for row in cursor.fetchall():
print (row)
conn.close()
关键字 含义 性能影响 SCAN TABLE 全表扫描 性能差,数据量大时避免 SEARCH TABLE 使用索引查找 性能好 USING INDEX 使用了索引 正面指标 USING COVERING INDEX 覆盖索引(无需回表) 最佳性能
避免 SELECT \*,只查询需要的列
避免在索引列上使用函数或类型转换
大数据量分页使用游标或延迟关联
一句话总结 :执行计划是 SQL 优化的"体检报告",学会读懂它,就能找到性能瓶颈。
4.5 ORM 工作原理 ORM 不是魔法,它只是把繁琐的 SQL 操作封装成了优雅的 Python 代码。
Python 对象操作 -> ORM 引擎 -> SQL 生成器 -> 执行 SQL -> 结果映射回对象
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
engine = create_engine("sqlite:///test.db" )
Base = declarative_base()
class User (Base ):
__tablename__ = "users"
id = Column(Integer, primary_key=True )
name = Column(String)
age = Column(Integer)
Session = sessionmaker(bind=engine)
session = Session()
user = session.query(User).filter (User.age > 18 ).first()
优点 缺点 代码可读性强 性能开销(生成 SQL 需要时间) 数据库无关性(切换数据库方便) 复杂查询难以优化 自动处理关联关系 学习曲线陡峭 内置连接池和事务管理 隐藏了 SQL 细节,可能写出低效代码
user = session.query(User).first()
print (user.posts)
from sqlalchemy.orm import joinedload
user = session.query(User).options(joinedload(User.posts)).first()
一句话总结 :ORM 是效率与性能之间的平衡,简单操作用 ORM,复杂查询用原生 SQL。
5. Redis:追求极致的"快" 如果说 MySQL 是"厚重的铁柜子",那 Redis 就是"手边的便签纸"。它把数据存在内存里,速度比 MySQL 快几百倍。
5.1 Redis 能干啥?
缓存 :把经常访问的数据存起来,别每次都去翻慢吞吞的硬盘。
计数器 :比如文章的阅读量、点赞数。
验证码过期 :存一个验证码,设置 5 分钟后自动消失。
import redis
r = redis.Redis(host='localhost' , port=6379 , db=0 )
r.set ('session_token' , 'abc123456' , ex=60 )
token = r.get('session_token' )
print (f"Token: {token.decode('utf-8' )} " )
6. 综合实战:构建用户注册系统的后端逻辑 结合 SQLModel,写一个简单的用户注册和登录验证的逻辑。
from sqlmodel import SQLModel, Field, create_engine, Session, select
import hashlib
class User (SQLModel, table=True ):
id : int | None = Field(default=None , primary_key=True )
username: str = Field(index=True , unique=True )
password_hash: str
engine = create_engine("sqlite:///users.db" )
SQLModel.metadata.create_all(engine)
def register (username, password ):
pwd_hash = hashlib.sha256(password.encode()).hexdigest()
with Session(engine) as session:
new_user = User(username=username, password_hash=pwd_hash)
try :
session.add(new_user)
session.commit()
print (f"用户 {username} 注册成功!" )
except Exception:
print ("注册失败:用户名可能已存在。" )
def login (username, password ):
pwd_hash = hashlib.sha256(password.encode()).hexdigest()
with Session(engine) as session:
statement = select(User).where(User.username == username)
user = session.exec (statement).first()
if user and user.password_hash == pwd_hash:
print ("登录成功!欢迎回来。" )
return True
print ("登录失败:用户名或密码错误。" )
return False
register("admin" , "123456" )
login("admin" , "123456" )
7. 注意事项
密码永远别存明文 :如果你的数据库泄露了,明文密码会让你的用户想掐死你。用 hashlib 或者专门的 bcrypt 加密。
连接池 :在高并发项目里,频繁地打开、关闭数据库连接非常慢。要学会使用 create_engine 的连接池功能。
数据备份 :代码丢了可以重写,数据丢了公司可能就破产了。养成定期导出 SQL 备份的好习惯。
8. 练习题
题目 1:SQLite 事务操作
创建 accounts 表,包含 name 和 balance。
插入 A (1000 元) 和 B (500 元)。
使用事务:从 A 扣除 200,给 B 增加 200。
如果中途报错(模拟异常),则回滚事务,保证钱不丢。
import sqlite3
def transfer (from_user, to_user, amount ):
conn = sqlite3.connect(":memory:" )
cursor = conn.cursor()
cursor.execute("CREATE TABLE accounts (name TEXT, balance REAL)" )
cursor.executemany("INSERT INTO accounts VALUES (?, ?)" , [
("A" , 1000 ),
("B" , 500 )
])
conn.commit()
try :
print ("--- 开始转账 ---" )
cursor.execute("UPDATE accounts SET balance = balance - ? WHERE name = ?" , (amount, from_user))
cursor.execute("UPDATE accounts SET balance = balance + ? WHERE name = ?" , (amount, to_user))
conn.commit()
print ("转账成功!" )
except Exception as e:
conn.rollback()
print (f"转账失败,已回滚:{e} " )
finally :
cursor.execute("SELECT * FROM accounts" )
print (cursor.fetchall())
conn.close()
transfer("A" , "B" , 200 )
题目 2:SQLModel 关联查询 需求 :
定义两个模型:Team(球队)和 Player(球员)。
一个球队有多个球员(一对多)。
创建 'Lakers' 球队。
创建 'James', 'Davis' 属于 Lakers。
查询 Lakers 队的所有球员名字。
from typing import List , Optional
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
class Team (SQLModel, table=True ):
id : Optional [int ] = Field(default=None , primary_key=True )
name: str
players: List ["Player" ] = Relationship(back_populates="team" )
class Player (SQLModel, table=True ):
id : Optional [int ] = Field(default=None , primary_key=True )
name: str
team_id: Optional [int ] = Field(default=None , foreign_key="team.id" )
team: Optional [Team] = Relationship(back_populates="players" )
engine = create_engine("sqlite:///" )
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
lakers = Team(name="Lakers" )
p1 = Player(name="James" , team=lakers)
p2 = Player(name="Davis" , team=lakers)
session.add(lakers)
session.commit()
session.refresh(lakers)
print (f"球队:{lakers.name} " )
for p in lakers.players:
print (f"球员:{p.name} " )
题目 3:Redis 排行榜
使用 Redis 的 zadd 添加玩家分数:player1: 100, player2: 200, player3: 150。
使用 zrevrange 获取前 3 名玩家及其分数(从高到低)。
import redis
try :
r = redis.Redis(host='localhost' , port=6379 , db=0 )
r.delete('game_score' )
r.zadd('game_score' , {'player1' : 100 , 'player2' : 200 , 'player3' : 150 })
top_players = r.zrevrange('game_score' , 0 , 2 , withscores=True )
print ("--- 排行榜 ---" )
for rank, (name, score) in enumerate (top_players, 1 ):
print (f"第 {rank} 名:{name.decode()} - {int (score)} 分" )
except Exception as e:
print (f"Redis 连接失败,请检查服务是否启动:{e} " )
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online