编辑模式 · 点击文字即可修改 · Ctrl+S 导出 再次按 E 或点击左上角退出
模块 6.5 · 存储层改造

重构,在项目中使用 SQLite

只动存储层,前端一行不改

今天要换掉的,是地板下面那一层

项目没变,换的是它背后存东西的地方

🖥️
zero-to-tech
文字实验室
+ FastAPI 后端
→
存储
📄
history.json
一个文件
整存整取
🗄️
history.db
SQLite 数据库
能筛能排能限量
1
import json
from datetime import datetime, timezone
app = FastAPI()
# ... CORS ...
HISTORY_FILE = "history.json"
def load_history(): ...
def save_record(record): ...
@app.get("/api/profile")
def get_profile(): ...
def score_label(score): ...
@app.post("/api/analyze")
def analyze(req: AnalyzeRequest):
text = req.text
score = round(SnowNLP(text).sentiments, 2)
result = { ... }
save_record(result)
return result
@app.get("/api/history")
def history():
records = load_history()
records.reverse()
return records[:10]
接口层
对外的门。管的是接收什么、响应什么。
业务层
算分、算拼音、拼一条记录。管的是这件事本身怎么做。
存储层
东西存在哪儿、怎么存、怎么取。
123
一条纪律

重构,是代码职责的划分
不是行为的变更

重构只挪位置,不改行为。重构完跑一遍,但凡有一点不一样,就说明我们改错了——这既是纪律,也是验收的尺子。

拆分要由需求驱动,不为了对应分层而拆

三层,只拆出两个文件

backend/
main.py
接口层 + 业务层
今天一行都不用改,
所以不值得再拆开
storage.py
存储层
今天整个要被换掉,
所以值得单独立一道边界
JSON 文件→SQLite→PostgreSQL
1
今天的活儿,分两步

先搬家,后装修

01
搬家
把存储层原样搬进 storage.py。
还是那个 history.json,一个字都不改。
功能零变化
→
02
装修
把 storage.py 整个换成 SQLite 版。
这一步 main.py 几乎不用动。
换掉实现
12
"功能不能变"不是额外的纪律,它就是这个词的定义

什么才叫「重构」

在不改变外部可观察行为的前提下,
调整代码的内部结构
✓搬家 = 重构
行为必须不变,所以它自带一把尺子。
跑一遍 → 不一样就是错了
✗装修 = 换实现
行为本来就该变(数据都换地方了),没有这把尺子。
混着做 → 分不清是搬错还是换错
12
"一次给几条",是谁的决定?

那个写死的 10,站错了层

网页
💻
要 10 条
📱
要 20 条
前端
→
接口
/api/history
调用方
→
存储
storage.py
🙈 它不知道页面有多大
也不知道是手机还是电脑
也不该知道
动作归存储层,决定归调用方
123
六处改动,全都在 storage.py 这一个文件里

装修清单

现在(文件版)改成(数据库版)
1import jsonimport sqlite3
2HISTORY_FILE = "history.json"DB_FILE + 一个 get_conn()
3(文件时代没有这一步)init_db():启动时建表
4save_record:读全部 → 追加 → 整个写回一句 INSERT
5get_history:全量读 → 倒序 → 切片一句 SELECT … ORDER BY … LIMIT
6load_history删掉 (数据库不需要"整份读出来")

改完之后,main.py 只多两行——init_db 的 import,和启动时叫它一声。

功能做完了,还有四件小事

善后

01
数据不进 Git
.gitignore 加一行 backend/*.db。数据是运行时产生的,和代码不是一类东西。
02
history.json 退役
直接删掉,老记录不搬。但要知道数据迁移在真实项目里是一门正经手艺。
03
认识一下 ORM
把表包装成对象来操作,SQL 由框架代写(如 SQLModel、SQLAlchemy)。认个脸即可。
04
给 created_at 建索引
每次查历史都要按它排序。只给经常排序、经常筛选的列建,别见列就建。
1234
历史入库了,但还是全站一份

下一节,让历史分到每个人

会话:让服务器认得出「同一个浏览器」,给每条记录盖上它的记号——页面上,才能安全地只列出访客自己的历史。