SQLite连接几乎不会失败,问题多因事务未提交、游标未释放或执行方式错误;只写操作可用conn.execute()加commit(),读操作必须用cursor+fetch;路径需用绝对路径或内存数据库":memory:";批量插入应使用executemany()和显式事务。

SQLite 不需要“连接服务器”,sqlite3.connect() 实际上是打开或创建一个本地文件,只要路径可写、权限正常,连接就几乎不会失败——但后续操作卡住、数据没写入、查询为空,往往不是连接问题,而是事务没提交、游标没释放、或者用错了执行方式。
什么时候该用 conn.execute(),什么时候必须用 cursor?
简单说:只执行不返回结果的语句(如 CREATE TABLE、INSERT、UPDATE、DELETE),conn.execute() 可以直接用;但凡要读数据(SELECT),就必须走 cursor + fetch* 流程。
常见错误现象:
-
conn.execute("SELECT * FROM users")看起来执行了,但没任何输出——因为没取结果,也没报错 - 用
conn.execute()插入后查不到数据——忘了conn.commit() - 反复调用
conn.execute()建表报sqlite3.OperationalError: table xxx already exists——没加IF NOT EXISTS
正确做法:
- 建表、删表、写操作:优先用
conn.execute()+conn.commit() - 查操作:必须
conn.cursor()→cur.execute()→cur.fetchall()(或fetchone/fetchmany)→cur.close() - 所有涉及修改的操作,
commit()是硬性要求;只读查询不需要commit()
sqlite3.connect() 的路径陷阱与内存模式
传入相对路径(如 "data.db")时,SQLite 会按当前工作目录(os.getcwd())解析,不是脚本所在目录。你双击运行 .py 文件、用 IDE 运行、或从终端不同路径执行,实际生成的 .db 文件位置可能完全不同,导致“数据库不见了”“查不到刚插的数据”。
安全做法:
- 用绝对路径:
sqlite3.connect(os.path.join(os.path.dirname(__file__), "data.db")) - 或明确指定位置:
sqlite3.connect("/tmp/myapp.db") - 测试/临时计算场景,直接用内存数据库:
sqlite3.connect(":memory:")——进程退出即销毁,无需清理文件,且速度极快
注意::memory: 数据库不能跨连接共享,每个 connect(":memory:") 都是全新独立实例。
为什么批量插入慢?executemany() 和事务控制才是关键
用循环反复调用 conn.execute("INSERT ...") + commit(),每条记录都触发一次磁盘刷写,万级数据可能耗时几十秒。真正高效的写法是把多条语句包进一个事务,并用 executemany() 批量绑定参数。
示例对比:
- ❌ 慢:
for row in data: conn.execute("INSERT INTO t VALUES (?, ?)", row); conn.commit() - ✅ 快:
conn.executemany("INSERT INTO t VALUES (?, ?)", data); conn.commit()
更进一步优化:
- 显式开启事务:
conn.execute("BEGIN"),再批量插入,最后commit()——避免隐式事务开销 - 插入前关掉同步:
conn.execute("PRAGMA synchronous = OFF")(仅限可信环境,断电可能丢数据) - 大量建索引?等所有数据插入完再建,比边插边建快得多
容易被忽略的线程安全与资源泄漏
sqlite3 连接对象**不是线程安全的**。官方文档明确要求:每个线程必须使用自己独立的 conn 对象。共用一个连接在多线程下大概率触发 ProgrammingError: SQLite objects created in a thread can only be used in that same thread。
资源方面,conn 和 cursor 都应显式关闭。虽然 Python 垃圾回收最终会释放,但文件锁可能持续占用,尤其在 Windows 上会导致“数据库已锁定”错误。
最稳妥的写法是用 with 语句(注意:sqlite3.Connection 本身不支持 with,但可以包装):
conn = sqlite3.connect("app.db")
try:
conn.execute("INSERT INTO log (msg) VALUES (?)", ("start",))
conn.commit()
finally:
conn.close()
或者更推荐——把连接封装进函数,每次操作新建连接(SQLite 文件锁开销极小,适合频繁短连接场景)。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











