6.4 数据库正传--SQL与SQLite
数据库正传:为什么需要数据库,用 SQLite 演示它长什么样、怎么操作,并讲 SQL、索引、自增字段这些通识。
课时概要
数据库正传。为什么需要数据库(文件存储的痛人人都有,七步之内必有解药);用两个维度(关系型/非关系型 × 嵌入式/服务式)选型,落在 SQLite(关系型+嵌入式,一个 .db 文件)。在 REPL 里走通 CREATE/INSERT/SELECT/WHERE/DELETE,认清 SQL 注入 和 ? 占位符,再用 ORDER BY/DESC/LIMIT 体验数据库「只说要什么」的姿态,最后看它为什么不爆内存。
以上为 UP 主的 B 站官方简介,非观看笔记;只有跟完这一节才算自己的理解。
视频:【零到全栈】6.4-数据库正传--SQL与SQLite | 时长 51:35 | 模块 6 · 生态、数据与状态
讲义:模块 6.4:数据库正传——SQLite 与 SQL(李勃老师.com)
本节要点
- 两维度选型:关系型(表、SQL)vs 非关系型(文档/键值);嵌入式(一个文件、不用起服务)vs 服务式(独立进程守端口)。
- 文字实验室是结构化小数据、单应用 → 关系型 + 嵌入式 → SQLite:零安装、单文件、Python 自带。
- 增删改查:CREATE TABLE / INSERT / SELECT / DELETE;改完必须
conn.commit()才落盘(提交事务)。 WHERE千万别漏:DELETE FROM films不带条件 = 清空整张表。- SQL 注入:拼用户输入 = 把数据伪装成命令;铁律——SQL 里永不拼用户输入,值永远走
?占位符。 ORDER BY ... DESC LIMIT 10:只说「要什么」,数据库自己安排怎么扫、怎么排、怎么快。- 数据库不爆内存三招:LIMIT 只攥 N 把椅子 / 按页读盘+磁盘外排 / 索引(提前排好的目录)。
笔记正文(讲义整理)
选型两维度
| 维度 | 选项 | 代表 |
|---|---|---|
| 数据模型 | 关系型(表、SQL)/ 非关系型(NoSQL) | MySQL/PG/SQLite;MongoDB(文档)、Redis(键值) |
| 服务方式 | 嵌入式(一个 .db 文件)/ 服务式(独立进程守端口) | SQLite;MySQL(3306)、PG(5432) |
我们:结构化小数据、单应用、不想养常驻服务 → SQLite。它普及到手机里躺着几十个(微信聊天记录、浏览器历史)。
在 REPL 里走一遍
import sqlite3
conn = sqlite3.connect("test.db") # 没有就创建——就是硬盘上一个文件
cur = conn.cursor()
cur.execute("""
CREATE TABLE films (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT, language TEXT, release_date TEXT, created_at TEXT
)
""")
cur.execute(
"INSERT INTO films (title, language, release_date, created_at) "
"VALUES (?, ?, ?, datetime('now'))",
["肖申克的救赎", "英语", "1994-09-23"])
conn.commit() # ← 不 commit 改动不落盘
cur.execute("SELECT * FROM films WHERE language = ?", ["日语"]).fetchall()
cur.execute("DELETE FROM films WHERE id = ?", [2]); conn.commit()要点:id 自增、datetime('now') 是函数不加引号、SQLite 类型最精简(INTEGER/REAL/TEXT/BLOB,日期和布尔分别用 TEXT/0-1 凑)。
SQL 注入
拼出来的 SQL:"... WHERE title = '" + keyword + "'"——当片名是 ' OR '1'='1,引号提前闭合,'1'='1' 永真,整表被吐出来。
解法:占位符。值的位置只写 ?,值放进列表单独交给 execute:
cur.execute("SELECT * FROM films WHERE title = ?", [keyword]).fetchall()数据库认定 ? 处铁定是值,里面什么符号都只当纯数据。规则:永不拼用户输入。
ORDER BY / DESC / LIMIT
SELECT * FROM films ORDER BY created_at DESC LIMIT 5对比文件版:records.reverse(); records[:10](告诉程序怎么做)vs 这一行(只说要什么)。
为什么不爆内存
- 只要 N 条就只攥 N 把椅子:LIMIT 10 一开始就告诉数据库,前 10 条坐下,第 11 条起和当前最旧的比,椅子永远 10 把;
- 按页读盘 + 排不下摊到硬盘:表切成固定页,用哪页翻哪页;真要全排就把中间结果暂存磁盘临时文件;
- 索引:像字典检字表,提前把某列排好;常排序/常筛选的列才建(代价是占空间+拖慢写入)。底层是 B 树,插一条只局部动一下。
和 GFG / 课程笔记的连接
| 这节内容 | GFG / 已学 |
|---|---|
sqlite3 模块 | GFG 有专门的 SQLite/DB 章节——connect/cursor/execute/commit 是标准姿势 |
conn.commit() 事务 | 6.3 文件存储时点过「事务」,今天第一次真正用到 |
? 占位符 | 安全习惯;和 4.6 CVE 同一精神——安全是每行代码的习惯 |
| 索引/B 树 | 数据结构;GFG/计算机专业课主线,这里先认个名 |
| 「只说要什么」 | 对比 6.3 手写 load_history/reverse/slice,姿态之别 |
GFG 里的 sqlite3 教程是「照着操作」,这里是带着自己 history 表的需求去理解为什么这么用。
关键概念
- 关系型数据库:数据摆成固定表、固定列类型,用 SQL 增删改查。
- 嵌入式:数据库就是一个文件,不用起服务(SQLite);服务式是独立进程守端口。
- cursor:往数据库递 SQL 的手柄。
- 主键 PRIMARY KEY / 自增 AUTOINCREMENT:每行的唯一身份证,数据库自动发号。
- commit:把改动真正落盘;不 commit 就退出,改动不算数。
- SQL 注入:把用户输入拼进 SQL,被当成命令执行;用
?占位符根治。 - 索引:提前把某列排好的目录(B 树),查得快但占空间、拖慢写。
代码 / 实操
cd ~ && python3
# import sqlite3
# conn = sqlite3.connect("test.db"); cur = conn.cursor()
# 建表 / INSERT / SELECT / DELETE / commit(见正文)
# ORDER BY created_at DESC LIMIT 5
python3 seed_data.py # 灌 24 部电影可视化工具:DB Browser for SQLite / DBeaver(开源免费);付费可选 DataGrip / Navicat。
我的收获
- 数据库不是「高级版文件」,是姿态变了:我只说要什么,怎么扫怎么排交给它。
?占位符防注入这个坑,光读理论不如看那部叫' OR '1'='1的电影真的能被存进去——数据就是数据。- LIMIT N 只攥 N 把椅子这个比喻,一下解释了「百万行排序为什么不爆内存」。
待深入
(待填:没听懂、想回头查的。)