自动提交默认开启导致每条SQL立即生效且无法回滚,多语句执行易引发数据不一致,应显式关闭并用BEGIN/COMMIT包裹操作;MySQL用SET autocommit=0,PostgreSQL需会话级设置;ORM混用原生SQL时须确认实际autocommit状态。

自动提交让每条 SQL 都“秒生效”,但你根本没机会后悔
默认开启的自动提交(autocommit=1)意味着每条 INSERT、UPDATE、DELETE 执行完就直接落盘,没有事务包装,也没有 ROLLBACK 的余地。这不是便利,是裸奔——尤其当你在命令行或脚本里手抖输错 WHERE 条件时,数据就没了,连补救窗口都没有。
批处理中间出错,结果可能“半截提交”
在自动提交模式下执行多条语句(比如用 mysql -e 或 JDBC 批量 addBatch()),行为完全取决于驱动和数据库实现:有的逐条提交,有的等整批跑完再统一提交;更糟的是,某些数据库遇到错误后,已执行的语句照常提交,后续语句跳过——造成数据不一致。这正是为什么规范要求:要保证原子性,必须关掉自动提交,显式用 BEGIN / COMMIT 包裹整批操作。
MySQL 和 PostgreSQL 的“默认很像,但关法不同”
MySQL 关自动提交很简单:SET autocommit = 0;,之后所有 DML 都进事务;PostgreSQL 默认也自动提交,但它没有 autocommit 变量,而是靠客户端行为控制——psql 里用 \set AUTOCOMMIT off,JDBC 则调用 connection.setAutoCommit(false)。别想当然以为设个全局变量就一劳永逸,PostgreSQL 里每个会话都得单独关。
存储过程里循环 + 自动提交 = 性能灾难 + 状态不可控
有人写存储过程边插边 COMMIT,以为稳妥,实则埋雷:
- 每次
COMMIT都触发 redo log 刷盘,10000 次插入变成 10000 次磁盘 I/O,慢十倍不止 - 若第 5001 次失败,前 5000 条已提交,无法整体回滚,业务逻辑断层
- InnoDB 下还可能因长事务锁表,阻塞其他连接
正确做法是:关自动提交 → 循环内只 INSERT → 循环外统一 COMMIT,出错则 ROLLBACK。
最常被忽略的一点:很多 ORM(如 SQLAlchemy、Django ORM)默认接管事务,但一旦你混用原生 SQL 或直连 connection,自动提交状态就脱离框架控制——此时看似“没写 COMMIT”,数据却早已落地。务必确认底层连接的实际 autocommit 值,而不是依赖框架文档的默认描述。










