Python sqlite3 with 代码块退出后为什么没有提交数据
如果 Python 的 sqlite3 写入在 with 代码块后仍然查不到,先不要把问题归咎于 SQLite“没有保存”。最常见的原因是:退出的并不是一个打开事务的连接上下文,或者你把“提交”误当成了“关闭连接”。正确做法是先确认事务模式,再决定是否显式调用 commit();需要跨线程时,还要让连接归属和写入同步保持清楚。
with con:正常退出时提交、异常退出时回滚,但不会自动关闭con。autocommit=True下每条写入按 SQLite 自动提交处理,commit()没有额外作用。- 默认
check_same_thread=True,多线程应优先采用“每线程一个连接”,不要共享一个写连接。
with sqlite3.connect() 到底提交了什么
连接对象实现了上下文管理器,但它的职责很窄:只处理代码块结束时的事务提交或回滚。下面的写法可以提交插入结果,但连接仍然存在,真正关闭它仍要调用 close()。
import sqlite3
con = sqlite3.connect("notes.db")
try:
con.execute("CREATE TABLE IF NOT EXISTS note(id INTEGER PRIMARY KEY, body TEXT)")
with con:
# 代码块正常结束,当前打开的事务会提交
con.execute("INSERT INTO note(body) VALUES (?)", ("会议记录",))
finally:
# with 不负责释放连接,关闭前保留显式的资源边界
con.close()
这里有两个容易混淆的点。第一,with con: 不会凭空创建事务;它离开时只处理已经打开的事务。第二,若代码块中抛出未捕获异常,连接会回滚这次事务,异常本身仍会继续向外抛出。因此“代码块退出了”不等于“数据一定提交了”,还要看退出路径和连接当时是否处于事务中。
当你使用Python sqlite3模块的with语句包裹数据库连接操作,退出上下文后发现写入的数据没有落库,核心原因是sqlite3默认的事务提交行为和with上下文管理器的自动处理逻辑有冲突,只有在上下文块内没有抛出异常的前提下,改动才会被自动提交。

先区分事务模式,再决定 commit 写法
“要不要写 commit()”取决于连接的事务控制方式。现代 Python 文档推荐使用 autocommit 明确表达策略;如果项目仍使用默认的传统控制,则要继续看 isolation_level。
| 配置 | 写入表现 | 排查建议 |
|---|---|---|
autocommit=False | 事务持续打开,需显式提交或回滚 | 把一个业务批次包在 with con: 或显式 commit() 中 |
autocommit=True | 使用 SQLite 自动提交,commit() 不产生额外动作 | 不要把 commit() 当成“刷新查询”的开关 |
isolation_level=None | 传统模式下不隐式开启事务 | 需要原子批量写入时显式执行 BEGIN、commit() 和 rollback() |
一个稳妥的批量写入函数应该把成功和失败路径写在一起,让调用方知道何时数据已经交给数据库:
def save_notes(path, rows):
con = sqlite3.connect(path)
try:
# 一个函数调用对应一个事务,失败时整体回滚
with con:
con.executemany(
"INSERT INTO note(body) VALUES (?)",
((row,) for row in rows),
)
except sqlite3.Error:
# 让上层看到数据库错误,不把失败伪装成成功
raise
finally:
# 提交/回滚与关闭是两个独立动作
con.close()
如果设置了 isolation_level=None,不要只加一个 with con: 就期待它替你建立批量事务;应明确执行 BEGIN,并在异常时调用 rollback()。反过来,如果使用 autocommit=True,每次写入的边界已经不同,重复调用 commit() 只会让代码看起来更复杂。
多线程时别把提交问题误判成线程问题
当写入代码放到线程池后,常见现象是一个线程能查到,另一个线程却报错或看不到数据。默认情况下,连接只能由创建它的线程使用,跨线程会触发 ProgrammingError。把 check_same_thread=False 打开只能绕过这层检查,并不会自动替你串行化写操作。
更容易维护的方案是每个工作线程创建自己的连接,主线程只负责汇总结果;若业务必须共享连接,就要使用锁把写事务包住,并明确谁负责关闭连接。
import sqlite3
from concurrent.futures import ThreadPoolExecutor
def write_one(path, body):
con = sqlite3.connect(path)
try:
with con:
# 连接由当前工作线程创建和使用,避免跨线程复用
con.execute("INSERT INTO note(body) VALUES (?)", (body,))
finally:
con.close()
with ThreadPoolExecutor(max_workers=2) as pool:
# 每个任务独立拥有连接,提交边界也独立
list(pool.map(lambda text: write_one("notes.db", text), ["甲", "乙"]))

把“写入但看不到”收敛成检查清单
最后可以用一个独立连接验证结果,避免把当前连接里的可见数据误认为已经落盘:
def count_notes(path):
con = sqlite3.connect(path)
try:
# 独立连接读取,验证上一个连接是否真正提交
return con.execute("SELECT COUNT(*) FROM note").fetchone()[0]
finally:
con.close()
排查时按这个顺序看,通常很快就能定位:
- 写入后检查
con.in_transaction,确认是否还有未提交事务。 - 确认是否真的进入了
with con:,以及代码块是否因异常走了回滚路径。 - 检查是否在查询前误用了另一个数据库路径,尤其是相对路径。
- 检查
autocommit、isolation_level和check_same_thread的实际值。 - 多线程场景用独立连接查询,并让每个连接在所属线程完成关闭。
这几项中,最常被忽略的是“连接没有关闭”和“事务没有提交”是两件事。关闭连接前仍有待处理变更时,不能指望它替你保存;相反,已经提交的数据也不需要靠关闭动作才能被其他连接看到。
常见问题
with con 会自动关闭 sqlite3 连接吗?
不会。它只在离开代码块时提交或回滚事务,连接需要显式调用 close(),也可以把连接关闭放进自己的资源管理结构。
为什么 commit() 调用了却没有变化?
先看是否处于 autocommit=True,或当前根本没有打开事务;这两种情况下 commit() 都可能没有可见的额外动作。
check_same_thread=False 能解决多线程写入吗?
它只关闭线程归属检查,不能解决并发写入的同步、事务互相覆盖和连接关闭责任。除非有明确的锁策略,否则优先给每个线程创建连接。
Go 导入 internal 包被拒绝时怎么按目录规则定位
- 上一篇
- Go 导入 internal 包被拒绝时怎么按目录规则定位
- 下一篇
- Go 嵌入静态资源后为什么 os.Stat 找不到它
-
- 文章 · python教程 | 1小时前 | 并发 · 日志 · Python教程 · 多进程 · 排障 · Python Fork multiprocessing 多进程日志 spawn QueueHandler QueueListener
- Python 多进程日志互相交错时怎么设计输出
- 300浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python multiprocessing spawn 下子进程重复导入怎么处理
- 107浏览 收藏
-
- 文章 · python教程 | 5小时前 |
- Python asyncio TaskGroup 一个任务失败时其他任务怎么收尾
- 475浏览 收藏
-
- 文章 · python教程 | 6小时前 |
- Python Path.iterdir 遇到权限错误时怎么继续扫描
- 468浏览 收藏
-
- 文章 · python教程 | 9小时前 |
- Python 3.14 free-threaded 构建选择前要检查哪些扩展兼容性
- 270浏览 收藏
-
- 文章 · python教程 | 9小时前 |
- Python multiprocessing spawn 模式为什么需要 main 保护
- 488浏览 收藏
-
- 文章 · python教程 | 11小时前 |
- Python typing Protocol 怎么为第三方对象定义最小接口
- 298浏览 收藏
-
- 文章 · python教程 | 13小时前 |
- Python subprocess 管道死锁时怎么读取 stdout 和 stderr
- 459浏览 收藏
-
- 文章 · python教程 | 14小时前 | 性能优化 · 多线程 · Python教程 · 日志处理 · Python logging queue.Queue 后台线程 QueueHandler QueueListener
- Python logging QueueHandler 怎么把日志写入后台线程
- 174浏览 收藏
-
- 文章 · python教程 | 15小时前 |
- Python zoneinfo 找不到时区数据库时怎么部署
- 326浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 19次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 175次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 110次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 37次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 17次使用
-
- Python sqlite3 Connection serialize 怎么导出数据库快照:备份窗口、内存占用与恢复校验
- 2026-08-26 501浏览
-
- Python监控网页状态:requests异常处理实战
- 2026-05-29 501浏览
-
- TensorFlow模型部署为API的TF Serving方法
- 2026-05-26 501浏览
-
- Python字符串编码转换:encode与decode详解
- 2026-05-16 501浏览
-
- TensorFlow裁剪无用算子方法详解
- 2026-05-15 501浏览
