SQLite 在自动化脚本里的四个正确姿势

举报
yd_217517564 发表于 2026/11/01 00:16:37 2026/11/01
【摘要】 SQLite 在自动化脚本里的四个正确姿势小工具、定时任务、爬虫的中间状态,用 SQLite 比上 MySQL 省事得多。但默认配置下,它在并发和崩溃时的表现会让你怀疑人生。四个设置能解决大部分问题。 一、打开 WAL,让读写不再互相阻塞默认的 rollback journal 模式下,写操作会阻塞所有读。加一行:import sqlite3conn = sqlite3.connect("...

SQLite 在自动化脚本里的四个正确姿势

小工具、定时任务、爬虫的中间状态,用 SQLite 比上 MySQL 省事得多。但默认配置下,它在并发和崩溃时的表现会让你怀疑人生。四个设置能解决大部分问题。

一、打开 WAL,让读写不再互相阻塞

默认的 rollback journal 模式下,写操作会阻塞所有读。加一行:

import sqlite3

conn = sqlite3.connect("state.db")
conn.execute("PRAGMA journal_mode=WAL")

WAL 下写不阻塞读,读也不阻塞写。副作用是多了 -wal 和 -shm 两个文件,备份时要一起拷,或者用 VACUUM INTO 做一致性快照。

二、设置 busy_timeout,别让程序直接抛 locked

两个进程同时写,默认行为是立刻抛 database is locked。多数脚本没有重试逻辑,于是任务失败。

conn.execute("PRAGMA busy_timeout=5000")   # 毫秒

它让 SQLite 在锁冲突时等待,而不是立刻失败。配合 WAL,能覆盖绝大多数"两个定时任务撞车"的场景。

三、批量写要显式开事务

SQLite 默认每条语句自动提交,一万条插入就是一万次 fsync。正确写法:

with conn:                      # 自动 BEGIN / COMMIT / 出错 ROLLBACK
    conn.executemany("INSERT INTO item(key, payload) VALUES(?, ?)", rows)

实测差别在几十倍量级:1 万条记录,逐条提交 8 秒以上,单事务 0.1 秒左右。

四、用 INSERT … ON CONFLICT 做幂等

定时任务一定会重跑,别用"先查再插"——两次查询之间可能有并发。让数据库保证唯一性:

conn.execute("""
INSERT INTO item(key, payload, updated_at)
VALUES (?, ?, datetime('now'))
ON CONFLICT(key) DO UPDATE SET
  payload = excluded.payload,
  updated_at = excluded.updated_at
""", (key, payload))

前提是 key 上有 UNIQUE 或 PRIMARY KEY。这样重跑不会产生重复行,也不会覆盖掉别的字段。

补充:什么时候不该用 SQLite

  • 多机写入:SQLite 是单机文件,NFS 上并发写会损坏
  • 高频写 + 长事务:WAL 也会膨胀,需要定期 checkpoint
  • 需要网络访问:那是 PostgreSQL/MySQL 的领域

单机上"一个脚本 + 一个状态库"的场景,上面四条足够了。真正的坑从来不是 SQLite 性能不够,而是没人给它设 busy_timeout,然后在大半夜收到 database is locked。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。