Python 写 SQLite:事务提交和关闭连接是两件事

举报
TechCao 发表于 2026/10/31 06:05:15 2026/10/31
【摘要】 Python 的 SQLite 连接上下文负责事务提交与回滚,并不会关闭连接。通过一个唯一约束失败的批量写入示例,说明怎样组合 with conn 与 contextlib.closing,让事务边界、异常处理和连接生命周期各自清楚。

把几条数据写入 SQLite,看起来只需要执行几次 INSERT。但如果第二条数据违反唯一约束,第一条已经写入的数据该怎么办?把相关写入放进同一个事务,可以让这批操作一起成功,或者一起撤销。另一个容易忽略的问题是:完成事务,并不等于关闭数据库连接。

用一个事务包住一批写入

下面是一个可以单独运行的例子。表名和字段名固定,数据通过占位符传递。示例使用 sqlite3 默认的事务控制方式,没有设置 isolation_level=None 或 autocommit=True。

import sqlite3
from contextlib import closing
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    db_path = Path(directory) / "demo.sqlite3"
    with closing(sqlite3.connect(db_path)) as conn:
        conn.execute(
            "CREATE TABLE note (name TEXT UNIQUE NOT NULL)"
        )
        with conn:
            conn.execute("INSERT INTO note VALUES (?)", ("原有记录",))

        try:
            with conn:
                conn.executemany(
                    "INSERT INTO note VALUES (?)",
                    [("新记录",), ("原有记录",)],
                )
        except sqlite3.IntegrityError:
            print("本批写入已回滚")

        rows = conn.execute("SELECT name FROM note").fetchall()
        print(rows)  # [('原有记录',)]

第一次 with conn 正常结束,原有记录被提交。第二次批量插入中,“新记录”先成功执行,随后“原有记录”与唯一约束冲突。异常离开 with conn 时,当前事务回滚,因此数据库里只剩第一次已经提交的记录。

这里的 CREATE TABLE 是初始化步骤。不要据此推断建表、迁移和任意 SQL 都会自动进入同一个事务。Python 的事务控制配置会影响隐式 BEGIN 的时机;复杂迁移应明确设计事务边界,并针对所用版本验证。

异常要离开事务代码块

连接的上下文管理器会在代码块正常结束时提交已有事务,在异常退出时回滚。若在 with conn 内部捕获错误并直接忽略,代码块可能正常结束,前面已经执行的写入就可能被提交。因此,示例把 except 放在事务代码块外面。

如果业务确实允许部分成功,需要明确定义哪些记录可以保留,必要时使用保存点,而不是无意中吞掉异常。也应避免在这批操作中途手动调用 commit(),否则后面的回滚无法撤销已提交的数据。

提交之后仍要关闭连接

with conn 管理事务,退出时不会自动关闭连接。外层 contextlib.closing 才负责在结束时调用 close(),包括出现异常的情况。两层代码块表达了不同职责:内层决定提交或回滚,外层释放连接和相关资源。

关闭连接也不能代替提交。对于仍有未提交写入的连接,不要期待 close() 自动帮你保存。把成功路径的提交和资源释放分别写清楚,程序的行为才容易检查。

占位符解决的是数据值传递。它不能直接替代表名或列名;需要动态选择字段时,应在调用方维护允许列表,避免拼接不受控制的标识符。

最后,事务并不能让所有并发写入同时成功。多个连接竞争写锁时仍可能遇到锁等待或超时,耗时的网络请求不适合放在写事务里。本地验证可以先覆盖正常提交、唯一约束失败后整批回滚,以及异常后连接释放三个场景,再接入真实业务。

本文由 AI 辅助撰写;示例已在本地验证正常提交、批量插入失败后的回滚,以及连接关闭后拒绝继续执行 SQL 的行为。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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