606 SQLite 嵌入式数据库使用¶
一句话概述:SQLite 是全球部署量最大的数据库,整个数据库就是一个文件,零配置、零服务器,直接嵌入应用程序中使用,手机/浏览器/桌面应用都在用它。
核心知识点速查表¶
| 知识点 | 说明 |
|---|---|
| 最新版本 | SQLite 3.47+(2025年) |
| 核心特性 | 零配置、单文件、ACID事务、小于1MB |
| 并发模型 | 多读单写,WAL模式支持读写并发 |
| 适用场景 | 移动应用、桌面软件、嵌入式、数据分析、测试 |
| 不适用 | 高写入并发、多服务器共享数据 |
| 许可证 | 公共领域(Public Domain),无任何限制 |
一、安装配置¶
1.1 安装¶
# Ubuntu 安装
sudo apt install sqlite3 # 安装 SQLite 命令行
sqlite3 --version # 查看版本
# macOS(自带)
sqlite3 --version # macOS 预装了 SQLite
# Python(自带,无需安装)
python3 -c "import sqlite3; print(sqlite3.sqlite_version)" # 查看版本
# pip 安装增强版(可选)
pip install pysqlite3 # Python 增强版 SQLite 绑定
1.2 创建数据库¶
# 白话:SQLite 数据库就是一个文件,创建数据库=创建文件
sqlite3 mydb.db # 打开/创建数据库文件
# 进入交互模式后就可以执行 SQL 了
# 常用 dot 命令(SQLite 特有的管理命令)
.help # 查看所有命令
.databases # 列出已打开的数据库
.tables # 列出所有表
.schema users # 查看建表语句
.mode column # 以表格形式显示查询结果
.headers on # 显示列名
.quit # 退出
二、基本使用¶
2.1 建表与 CRUD¶
-- 创建表
CREATE TABLE IF NOT EXISTS users ( -- IF NOT EXISTS 防止重复创建
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自增主键
name TEXT NOT NULL, -- 姓名,不允许为空
email TEXT UNIQUE, -- 邮箱,唯一约束
age INTEGER DEFAULT 0, -- 年龄,默认值 0
created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- 创建时间,自动填当前时间
);
-- 插入数据
INSERT INTO users (name, email, age) VALUES ('张三', 'zhangsan@example.com', 25);
INSERT INTO users (name, email, age) VALUES ('李四', 'lisi@example.com', 30);
-- 查询数据
SELECT * FROM users; -- 查所有
SELECT name, age FROM users WHERE age > 25; -- 条件查询
SELECT * FROM users ORDER BY age DESC LIMIT 10; -- 按年龄降序,取前10条
-- 更新数据
UPDATE users SET age = 26 WHERE name = '张三'; -- 更新张三的年龄
-- 删除数据
DELETE FROM users WHERE id = 1; -- 删除 id=1 的记录
2.2 Python 操作 SQLite¶
import sqlite3 # Python 标准库自带,无需安装
# 连接数据库(文件不存在会自动创建)
conn = sqlite3.connect('myapp.db') # 连接数据库文件
conn.row_factory = sqlite3.Row # 让查询结果可以用列名访问
cursor = conn.cursor() # 创建游标
# 创建表
cursor.execute('''
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
done INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
# 插入数据(使用参数绑定防止 SQL 注入!)
cursor.execute(
'INSERT INTO tasks (title) VALUES (?)', # ? 是占位符
('学习 SQLite',) # 参数用元组传入
)
# 批量插入
tasks = [
('学习 Python',),
('学习 Redis',),
('写毕业论文',),
]
cursor.executemany(
'INSERT INTO tasks (title) VALUES (?)',
tasks # 批量数据
)
conn.commit() # 提交事务(重要!不提交数据不会保存)
# 查询数据
cursor.execute('SELECT * FROM tasks WHERE done = ?', (0,))
for row in cursor.fetchall(): # 遍历所有结果
print(f"ID: {row['id']}, 标题: {row['title']}") # 用列名访问
# 更新数据
cursor.execute('UPDATE tasks SET done = 1 WHERE id = ?', (1,))
conn.commit()
# 关闭连接
conn.close() # 用完记得关闭
2.3 使用上下文管理器(推荐写法)¶
import sqlite3
def get_db():
"""获取数据库连接的推荐写法"""
conn = sqlite3.connect('myapp.db')
conn.row_factory = sqlite3.Row
conn.execute('PRAGMA foreign_keys = ON') # 开启外键约束(默认关闭!)
conn.execute('PRAGMA journal_mode = WAL') # 开启 WAL 模式(提升并发性能)
return conn
# 使用 with 语句自动管理事务
with get_db() as conn: # with 语句自动 commit 或 rollback
conn.execute(
'INSERT INTO tasks (title) VALUES (?)',
('新任务',)
)
# with 块结束时自动提交
三、高级用法¶
3.1 PRAGMA 优化¶
-- PRAGMA 是 SQLite 特有的配置命令
-- 白话:调整 SQLite 的"内部开关"来优化性能
PRAGMA journal_mode = WAL; -- 开启 WAL 模式(允许读写并发,性能大幅提升)
PRAGMA synchronous = NORMAL; -- 同步模式(NORMAL 比 FULL 快,安全性足够)
PRAGMA cache_size = -64000; -- 缓存 64MB(负数单位是 KB)
PRAGMA foreign_keys = ON; -- 开启外键约束(SQLite 默认不检查外键!)
PRAGMA busy_timeout = 5000; -- 写入锁等待 5 秒(避免 database is locked 错误)
PRAGMA temp_store = MEMORY; -- 临时表存在内存里(更快)
3.2 JSON 支持¶
-- SQLite 内置 JSON 函数,可以存储和查询 JSON 数据
CREATE TABLE configs (
id INTEGER PRIMARY KEY,
data TEXT -- JSON 数据存为 TEXT
);
INSERT INTO configs (data) VALUES
('{"app": "myapp", "version": "1.0", "features": ["search", "export"]}');
-- 提取 JSON 字段
SELECT json_extract(data, '$.app') AS app_name FROM configs; -- → "myapp"
SELECT json_extract(data, '$.features[0]') FROM configs; -- → "search"
-- 修改 JSON
UPDATE configs
SET data = json_set(data, '$.version', '2.0') -- 修改 version 字段
WHERE id = 1;
3.3 全文搜索(FTS5)¶
-- FTS5 是 SQLite 的全文搜索扩展
-- 白话:可以像搜索引擎一样搜索文本内容
-- 创建全文搜索虚拟表
CREATE VIRTUAL TABLE articles_fts USING fts5(
title, -- 标题
content, -- 内容
tokenize='unicode61' -- 分词器
);
-- 插入数据
INSERT INTO articles_fts VALUES ('Python入门', 'Python是一种编程语言');
INSERT INTO articles_fts VALUES ('Redis缓存', 'Redis是内存数据库');
-- 全文搜索
SELECT * FROM articles_fts WHERE articles_fts MATCH 'Python'; -- 搜索包含 Python 的
SELECT * FROM articles_fts WHERE articles_fts MATCH 'Python OR Redis'; -- OR 查询
SELECT highlight(articles_fts, 0, '<b>', '</b>') FROM articles_fts -- 高亮匹配词
WHERE articles_fts MATCH 'Python';
3.4 批量导入 CSV¶
# 命令行快速导入 CSV 文件
sqlite3 mydb.db
.mode csv # 设置 CSV 模式
.import data.csv my_table # 导入 CSV 到表(表不存在会自动创建)
# Python 导入 CSV
import csv
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
with open('data.csv', 'r') as f:
reader = csv.DictReader(f) # 用表头作为字段名
for row in reader:
cursor.execute(
'INSERT INTO my_table (name, value) VALUES (?, ?)',
(row['name'], row['value'])
)
conn.commit()
conn.close()
四、常见报错与解决¶
4.1 数据库被锁¶
原因:另一个进程正在写入 解决:
# 方法1:设置超时等待
conn = sqlite3.connect('mydb.db', timeout=10) # 等待最多10秒
# 方法2:开启 WAL 模式(推荐)
conn.execute('PRAGMA journal_mode = WAL') # 读写并发不冲突
4.2 外键不生效¶
原因:SQLite 默认不检查外键 解决:每次连接都要执行 PRAGMA foreign_keys = ON。
4.3 类型不匹配¶
注意:SQLite 不严格检查类型(这是设计如此),要在应用层做验证。使用 STRICT 表可以强制类型检查:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER NOT NULL
) STRICT; -- 严格模式,强制类型检查
五、速查表¶
| 操作 | 命令 |
|---|---|
| 打开数据库 | sqlite3 mydb.db |
| 列出所有表 | .tables |
| 查看表结构 | .schema tablename |
| 导出为 SQL | .dump > backup.sql |
| 导入 SQL | .read backup.sql |
| CSV 导入 | .mode csv → .import file.csv table |
| CSV 导出 | .mode csv → .output data.csv → SELECT ...; |
| 开启 WAL | PRAGMA journal_mode = WAL; |
| 开启外键 | PRAGMA foreign_keys = ON; |
| 数据库大小 | SELECT page_count * page_size FROM pragma_page_count(), pragma_page_size(); |
六、同类工具对比¶
| 特性 | SQLite | PostgreSQL | MySQL | DuckDB |
|---|---|---|---|---|
| 类型 | 嵌入式 | 客户端/服务器 | 客户端/服务器 | 嵌入式 |
| 并发写入 | 单写 | 多写 | 多写 | 单写 |
| 部署复杂度 | 零 | 中 | 中 | 零 |
| 适合场景 | 应用内存储 | 通用后端 | Web 应用 | 数据分析 |
| JSON 支持 | 扩展 | 原生 JSONB | 支持 | 支持 |
| 文件大小 | <1MB | 数百MB | 数百MB | ~40MB |
选型建议:应用内嵌存储首选 SQLite;需要并发写入选 PostgreSQL/MySQL;数据分析选 DuckDB(同为嵌入式但专为分析优化)。SQLite 和 PostgreSQL/MySQL 不是竞争关系,SQLite 竞争的是 fopen()。
参考资料:SQLite 官方文档 | 适用场景说明 | Python sqlite3 文档