SQLite 入门(Python sqlite3)
SQLite 是零配置、单文件的嵌入式数据库:没有独立的服务进程,整个数据库就是磁盘上的一个文件,Python 标准库
sqlite3直接可用。它是世界上部署最广泛的数据库(所有手机、浏览器里都有)。环境见Python 环境与包管理,示例在 Python 3.13 全量验证。
什么时候选 SQLite
| 场景 | 选择 |
|---|---|
| 本地应用数据(桌面软件、CLI 工具) | SQLite |
| 移动端/嵌入式存储、网站原型、缓存文件 | SQLite |
| 多台服务器并发写入、高并发 Web 服务 | 客户端-服务器型(PostgreSQL、MySQL) |
SQLite 的写入是整库锁(同一线程只有一个写事务),读可以并发。读多写少、单机场景用它能省掉整套数据库部署。
连接与游标
import sqlite3
conn = sqlite3.connect("app.db") # 文件不存在会自动创建;":memory:" 表示内存库
cur = conn.cursor()
cur.execute("SELECT sqlite_version()")
cur.fetchone() # ('3.45.1',) 之类
conn.close() # 用完关闭
cursor 是执行语句的工作对象;一次连接可创建多个游标。
建表与数据类型
SQLite 只有五种存储类型:NULL、INTEGER、REAL、TEXT、BLOB(类型是"建议"而非强制,但请按规矩声明):
cur.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY, -- INTEGER PRIMARY KEY 等价于自增 rowid
name TEXT NOT NULL UNIQUE,
email TEXT,
score REAL DEFAULT 0,
created TEXT DEFAULT (datetime('now'))
)
""")
增删改查与参数绑定
# 插入:一律用 ? 占位符,参数以元组传入
cur.execute("INSERT INTO users (name, email, score) VALUES (?, ?, ?)",
("ada", "[email protected]", 90.0))
# 批量插入用 executemany
cur.executemany("INSERT INTO users (name, email) VALUES (?, ?)",
[("bob", "[email protected]"), ("eve", "[email protected]")])
conn.commit() # 写操作必须提交,否则丢失
# 查询
cur.execute("SELECT id, name, score FROM users WHERE score > ?", (0,))
rows = cur.fetchall() # [(1, 'ada', 90.0), (2, 'bob', 0.0), (3, 'eve', 0.0)]
row = cur.fetchone() # 逐行取
for r in cur.execute("SELECT name FROM users ORDER BY score DESC"):
print(r[0]) # 游标本身可迭代
# 更新与删除(同样必须绑定参数并提交)
cur.execute("UPDATE users SET score = ? WHERE name = ?", (95.0, "ada"))
cur.execute("DELETE FROM users WHERE name = ?", ("eve",))
conn.commit()
print(cur.lastrowid) # 最近一次 INSERT 的自增主键
第一戒律:绝不拼接 SQL 字符串
占位符让驱动负责转义与类型处理,注入与转义问题一并消失。事务
try:
with conn: # 进入时开启事务,块内成功则自动 commit
cur.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
cur.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
# 中间任何异常 → 自动 rollback,两条都不会生效
except sqlite3.Error as e:
print("transfer failed:", e)
# 手动控制:conn.commit() / conn.rollback()
转账这类多步写操作必须包在事务里,保证"要么全成、要么全不动"。
按列名取值:sqlite3.Row
默认返回元组,按下标取列容易错位;把 row_factory 换成 sqlite3.Row 即可按名访问:
conn.row_factory = sqlite3.Row
row = conn.execute("SELECT id, name FROM users WHERE name = ?", ("ada",)).fetchone()
row["name"] # 'ada';row.keys() 列出列名
常用查询速记
SELECT * FROM users WHERE score >= 80 ORDER BY score DESC LIMIT 10;
SELECT dept, COUNT(*), AVG(score) FROM users GROUP BY dept;
SELECT u.name, d.title FROM users u JOIN depts d ON u.dept_id = d.id;
SELECT name FROM users WHERE name LIKE 'a%'; -- 通配:'%' 任意串 '_' 单字符
聚合函数 COUNT/SUM/AVG/MIN/MAX、JOIN、LIKE、LIMIT 都是标准 SQL 子集,语义与 PostgreSQL/MySQL 一致。
与 pandas 互通
import pandas as pd
df = pd.read_sql("SELECT * FROM users", conn) # 查询结果直接变 DataFrame
df.to_sql("users", conn, if_exists="append", index=False) # DataFrame 入库
处理流程可以组合成"SQLite 存数据 → pandas 分析"(pandas 用法见 NumPy 与 Pandas 速查)。
常见错误
| 错误 | 说明 |
|---|---|
| 写入后"消失" | 忘了 commit();连接关闭时未提交的事务被回滚 |
sqlite3.ProgrammingError: Incorrect bind |
参数必须是元组:单个值写 (value,) 而不是 (value) |
| 字符串拼接 SQL | 注入风险,见上文第一戒律 |
| 多线程共用一个连接 | 默认 check_same_thread=True 只允许创建线程使用;改为每线程各自建连接,或传 check_same_thread=False 并自行加锁 |
| 拼写错误的表名列名 | 默认运行时才报错(OperationalError: no such table);开发期写几条查询当冒烟测试 |
| 数据库文件被锁 | 另一进程持写锁(database is locked);缩短写事务、或设置 timeout= 参数 |
延伸:多进程并发写、主从备份属于 SQLite 的进阶话题;一旦超出单机单写模型的范围,就该迁移到 PostgreSQL 这类服务器型数据库。