答案:insert前必须显式开启事务,否则每条都是独立提交。python中pymysql默认autocommit=true,需先设conn.autocommit(false)并执行begin;sqlite3默认autocommit=false但须手动执行begin;mysql命令行须显式start transaction;多条insert必须包裹在同一事务内,异常时必须在except中调用rollback()确保数据一致性。

INSERT前必须显式开启事务,否则每条都是独立提交
SQLite、MySQL 默认 autocommit=True(尤其 Python 的 pymysql),这意味着每个 INSERT 语句执行完立刻生效,根本没机会回滚。你以为包在代码 try/except 里就安全了?错——数据库层面已经提交了。
- Python 中用
sqlite3:默认 autocommit=False,但必须手动调用conn.execute("BEGIN")或conn.isolation_level = None后再执行BEGIN,不能只靠上下文管理器 - Python 中用
pymysql:默认 autocommit=True,得先设conn.autocommit(False),再conn.begin()或直接执行BEGIN - MySQL 命令行:
START TRANSACTION;或BEGIN;必须显式写,不能省 - 漏掉这一步,后面所有
INSERT都是“孤勇者”,失败了也撤不回来
多条INSERT必须用同一事务包裹,且失败时立即ROLLBACK
转账要扣A加B,插入订单要写主表+明细表+日志——这些 INSERT 必须在一个事务里,否则中间出错就会留下脏数据。关键不是“写了COMMIT”,而是“出错时有没有ROLLBACK”。
一款AI工具,主要用于将编码任务调度到本地 OpenAI Codex CLI,支持后台执行、状态轮询以及可交互式回答的澄清问题。适用于 OpenClaw 需要……,适合需要提升相关任务效率的用户。
- 别依赖程序逻辑判断成功后再
COMMIT;要在异常捕获块里明确执行ROLLBACK,例如 Python 的except中调用conn.rollback() - 不要把
INSERT拆成多个事务执行,比如“先插用户,再插地址”,万一第二步失败,用户记录就成了孤儿数据 - SQLite 不支持
SAVEPOINT在INSERT中做局部回滚,想部分撤销就得自己拆逻辑,别指望数据库兜底 - MySQL 支持
SAVEPOINT,但仅限同个事务内,跨连接无效
INSERT失败常见原因:约束冲突比语法错误更隐蔽
INSERT 报错往往不是“SQL写错了”,而是违反了数据库层的约束——这类错误容易被忽略,直到线上出现重复主键或空字段。
-
UNIQUE constraint failed:试图插入重复的email或order_no,说明应用层没做去重,或并发写入撞了 -
NOT NULL constraint failed:字段定义了NOT NULL,但INSERT没给值,也没设DEFAULT -
FOREIGN KEY constraint failed:插入子表记录时,关联的父记录还没提交(或根本不存在),尤其在事务中跨表插入时极易发生 - 解决办法不是绕过约束,而是提前查、显式处理:比如先
SELECT ... FOR UPDATE锁定父记录,再INSERT
批量INSERT更要警惕隐式事务边界和锁竞争
用 INSERT INTO ... VALUES (...), (...), (...) 一次插多行看似高效,但事务范围、锁粒度、错误定位都变得更复杂。
- 单条
INSERT失败会导致整批回滚,但错误信息通常只报第一行的问题,需检查全部输入数据 - MySQL InnoDB 对批量
INSERT会加间隙锁(gap lock),可能阻塞其他事务,尤其在REPEATABLE READ下 - SQLite WAL 模式未启用时,批量
INSERT可能触发表级锁,高并发下成为瓶颈 - 真正需要性能时,宁可拆成小批次(如每 100 行一个事务),也别贪一次插 10000 行——事务越长,锁持有时间越久,回滚成本越高
INSERT,背后都有数据库在默默记日志、加锁、判断是否该回滚。漏掉 BEGIN,就等于没上保险;没写 ROLLBACK,就等于把钥匙留在锁眼里。










