尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python重启项目数据库“被清空”的原因:sqlite3 commit 与配置文件排查指南

发布时间:2026/9/29 8:39:24

资讯中心
01
ARTICLE

Python重启项目数据库“被清空”的原因:sqlite3 commit 与配置文件排查指南

Python重启项目数据库“被清空”的原因:sqlite3 commit 与配置文件排查指南
1. 重启后数据消失先别怀疑人生你写了个 Python 小工具用 sqlite3 存用户、存配置、存爬下来的数据。跑起来一切正常insert没报错select当场也能查到。结果关掉程序、第二天再跑select *返回空列表表还在数据没了。第一反应通常是数据库文件被谁删了是不是路径写错了还是 sqlite3 有 bug我试过在同一个坑里蹲了半个下午最后发现根因朴素得让人想笑insert 之后没有 commit。sqlite3 默认不会自动提交事务你的写入停留在连接自己的事务缓冲里程序一退出连接一关这些改动就被回滚了。表结构之所以还在是因为create table if not exists这类 DDL 在某些情况下会触发隐式提交或者你之前某次运行恰好提交过于是出现「表在、数据没」的诡异现象。这篇就围绕 Python sqlite3 项目重启后数据丢失这个场景从三条线索切入commit 缺失、连接关闭方式、数据库文件路径漂移。每条都给出可复制的代码骨架和验证动作让你能自己定位到底是哪一环出了问题。适合刚接触 sqlite3 的 Python 开发者也适合被「数据被清空」折磨过、想彻底搞明白事务边界的人。2. 三条线索commit、连接、路径2.1 commit 缺失最常见也最隐蔽sqlite3 的 Python 驱动遵循 DB-API 规范默认isolation_level是空字符串意味着它自动开启事务但不会自动提交。你执行insert、update、delete后改动只在当前连接的事务里可见其他连接看不到程序退出后直接丢弃。import sqlite3 conn sqlite3.connect(user.db) c conn.cursor() c.execute(create table if not exists users(userid text primary key, password text)) c.execute(insert into users values(?, ?), (u001, pwd001)) # 到这里没报错但数据没落盘 conn.close() # 事务回滚数据消失正确做法是显式conn.commit()或者把连接设成自动提交模式。注意c.execute(commit)这种写法虽然能跑但语义上应该用连接对象的commit()更清晰也更安全。2.2 连接关闭方式close 之前有没有 commit很多人以为conn.close()会自动保存其实不会。close()只是释放连接资源未提交的事务会被回滚。如果你用with语句管理连接也要注意with sqlite3.connect(...)在退出时只提交或回滚事务不关闭连接这点和文件对象的with行为不一样。# 错误示范with 里没 commit退出时行为依赖 isolation_level with sqlite3.connect(user.db) as conn: conn.execute(insert into users values(?, ?), (u002, pwd002)) # 这里其实会提交但很多人误以为 with 会关闭连接真正危险的是手动close()前忘了commit()或者异常路径下commit()没执行到。2.3 路径漂移你以为写的是同一个文件第三个高频原因是数据库文件路径不一致。开发时用相对路径user.db在 PyCharm 里运行工作目录是项目根数据库落在根目录换成命令行python src/main.py运行工作目录变成src/于是又新建了一个空的user.db。你查的是新文件当然没数据。import os print(os.getcwd()) # 每次运行前打印工作目录能快速发现路径漂移 print(os.path.abspath(user.db))配置文件里的路径如果写的是相对路径同样会随启动方式变化。下面会给出基于settings.json和config.toml的路径校验片段。3. TaoToken 前置把模型接进排查流程排查这类问题时我习惯让模型帮我快速生成对比代码和检查清单省去翻文档的时间。TaoToken 是一个模型调用入口兼容常见 API 格式适合把对话模型接进日常开发流程。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。你需要先拿到 API Key在控制台创建即可https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建后到 API Keys 页面复制https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的调用示例。如果你只是想验证模型能不能正确解释 sqlite3 事务行为可以直接用模型对话页面https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。长期做编码和 Agent 任务的话Coding Plan 更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。Claude Code 相关接入参考https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。拿到 Key 后用环境变量管理别硬编码进代码export TAOTOKEN_API_KEY你的key4. 可复制配置连接骨架与路径校验4.1 sqlite3 连接与 commit 骨架下面这个骨架把连接、事务、异常回滚、关闭都包好了直接拿去改表名和 SQL 即可。import sqlite3 import logging from contextlib import contextmanager logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) DB_PATH user.db contextmanager def get_conn(db_pathDB_PATH): conn sqlite3.connect(db_path, timeout10) conn.row_factory sqlite3.Row try: yield conn conn.commit() logger.info(事务已提交) except Exception as e: conn.rollback() logger.error(事务回滚: %s, e) raise finally: conn.close() logger.info(连接已关闭) def init_db(): with get_conn() as conn: conn.execute( create table if not exists users( userid text primary key, password text not null ) ) def insert_user(userid, password): with get_conn() as conn: conn.execute(insert or replace into users values(?, ?), (userid, password)) logger.info(插入用户 %s, userid) def list_users(): with get_conn() as conn: rows conn.execute(select * from users).fetchall() return [dict(r) for r in rows] if __name__ __main__: init_db() insert_user(u001, pwd001) print(list_users())关键点yield之后先commit()再close()异常时rollback()。这样无论正常还是异常路径事务状态都是确定的。4.2 settings.json 路径校验如果你的项目用 JSON 配置加一段启动时校验能立刻发现路径漂移。import json import os def load_settings(pathsettings.json): with open(path, r, encodingutf-8) as f: cfg json.load(f) db_path cfg.get(db_path, user.db) abs_path os.path.abspath(db_path) cfg[db_path_abs] abs_path logger.info(数据库绝对路径: %s, abs_path) logger.info(文件是否存在: %s, os.path.exists(abs_path)) if os.path.exists(abs_path): logger.info(文件大小: %d 字节, os.path.getsize(abs_path)) return cfgsettings.json示例{ db_path: data/user.db, log_level: INFO }4.3 config.toml 路径校验用 TOML 的项目同理Python 3.11 自带tomllib。import tomllib import os def load_config(pathconfig.toml): with open(path, rb) as f: cfg tomllib.load(f) db_path cfg.get(database, {}).get(path, user.db) abs_path os.path.abspath(db_path) print(f数据库绝对路径: {abs_path}) print(f是否存在: {os.path.exists(abs_path)}) return cfgconfig.toml示例[database] path data/user.db timeout 10注意相对路径永远相对于当前工作目录不是脚本所在目录。要相对脚本定位用os.path.dirname(os.path.abspath(__file__))拼。5. 验证请求重启前后数据比对光看代码不够得用动作验证。下面这套流程能帮你确认数据到底有没有落盘。第一步运行插入脚本记录当前数据# before_restart.py from db import init_db, insert_user, list_users init_db() insert_user(u100, pwd100) print(插入后:, list_users())第二步另开一个进程模拟重启只读查询# after_restart.py from db import list_users print(重启后:, list_users())第三步用 sqlite3 命令行直接查文件绕开 Python 层sqlite3 user.db select * from users;如果 Python 查得到、命令行查不到说明你连的可能是另一个文件回到 4.2 打印绝对路径对比。如果两边都查不到基本就是 commit 没执行。第四步检查文件修改时间确认写入是否真的发生ls -l --time-stylefull-iso user.db插入前后时间戳没变说明数据没落盘。如果你想让模型帮你分析两次查询结果的差异可以把输出贴到模型对话里https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。需要程序化调用的话用 API 端点配合你的 Keyimport os import requests api_key os.environ[TAOTOKEN_API_KEY] resp requests.post( https://taotoken.net/api/chat/completions, headers{Authorization: fBearer {api_key}}, json{ model: gpt-4o-mini, messages: [ {role: user, content: sqlite3 insert 后没 commit程序退出数据会怎样} ] }, timeout30 ) print(resp.json()[choices][0][message][content])6. 本篇常见错排查6.1 报错database is locked多进程或多线程同时写同一个 sqlite 文件会锁。解决加timeout参数或改用 WAL 模式。conn sqlite3.connect(user.db, timeout10) conn.execute(pragma journal_modewal)6.2 表存在但数据为空回到第 2 节三条线索逐条查先打印os.path.abspath确认文件再用命令行select确认落盘最后检查代码里commit()是否在close()之前执行。6.3 with 语句没提交with sqlite3.connect(...)退出时会提交但如果你在with内部又手动close()了连接后续提交会失败。别在with里手动关连接。6.4 异常被吞导致没回滚用try/except包住 SQL 时如果except里只pass事务状态会悬空。要么rollback()要么让异常继续抛。6.5 路径含中文或空格sqlite3 对路径支持没问题但配置文件解析时注意编码。JSON 用encodingutf-8TOML 用二进制模式读。6.6 多线程共用连接sqlite3 连接默认不能跨线程。每个线程建自己的连接或用连接池。报错通常是SQLite objects created in a thread can only be used in that same thread。排障时如果拿不准事务边界把关键代码贴给模型让它帮你标出 commit 位置https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 拿 Key接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。7. 把 commit 写进肌肉记忆sqlite3 的数据丢失九成不是数据库坏了而是事务没提交、连接关早了、文件找错了。把第 4 节的get_conn骨架抄进你的项目每次写库都走这个上下文管理器commit 和 rollback 就不用你操心了。路径方面启动时打印一次绝对路径比事后 debug 省事得多。长期做 Python 编码和 Agent 任务的话Coding Plan 能帮你把模型调用固定下来https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。需要快速验证模型对 sqlite3 行为的解释用模型对话页面就行https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。控制台管理 Key 和用量https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。