MySQL客户端连接默认autocommit=1,由驱动主动设置而非服务器配置决定;关闭后须显式commit/rollback,否则断连丢弃事务;SELECT不加锁,仅FOR UPDATE等才加锁。

MySQL 连接里 autocommit 默认值到底是多少?
绝大多数 MySQL 客户端连接(包括命令行、Python 的 pymysql、mysql-connector-python)默认开启 autocommit,即值为 1。但注意:这个“默认”不是服务器全局配置决定的,而是客户端驱动在建立连接时主动发送 SET autocommit = 1 设置的。
容易踩的坑:
- 误以为改了 MySQL 配置文件里的
autocommit=1就能影响所有连接——其实它只对未显式设置autocommit的新连接起作用,而主流驱动基本都会覆盖它 - 在事务中执行 DDL(如
CREATE TABLE)会隐式提交当前事务,哪怕autocommit=0也拦不住
Python 中用 pymysql 关闭自动提交后,怎么安全地做事务?
关闭 autocommit 后,必须显式调用 commit() 或 rollback(),否则连接断开时事务直接丢弃,不报错也不回滚。
实操建议:
- 创建连接时显式传参:
pymysql.connect(..., autocommit=False) - 用
try/except/finally包裹事务逻辑,确保rollback()在异常时执行 - 避免在事务中调用
cursor.execute("SELECT ...")以外的语句(比如SHOW VARIABLES),某些语句会触发隐式提交 - 不要依赖连接对象的
close()自动回滚——它不会帮你做任何事
示例关键片段:
conn = pymysql.connect(..., autocommit=False)
try:
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
conn.commit() # 必须手动
except Exception:
conn.rollback() # 必须手动
finally:
conn.close()
autocommit=0 下执行 SELECT 会锁表吗?
不会。单纯执行 SELECT 不加 FOR UPDATE 或 LOCK IN SHARE MODE,即使在 autocommit=0 的事务里,也不会持有任何行锁或表锁,也不产生事务上下文。
但要注意:
- 如果之前已执行过写操作(如
UPDATE),那整个事务仍处于活跃状态,后续SELECT可能读到未提交的变更(取决于隔离级别) - InnoDB 默认隔离级别是
REPEATABLE READ,此时SELECT会基于事务启动时的快照读,不是实时读 - 想让
SELECT加锁,必须显式写成SELECT ... FOR UPDATE,否则和autocommit开关无关
PHP 的 mysqli 和 PDO 对 autocommit 的处理差异
mysqli 默认开启 autocommit,且提供 mysqli_autocommit($link, false) 函数控制;PDO 则更严格:只要用了 PDO::ATTR_AUTOCOMMIT => false,就必须调用 $pdo->commit() 或 $pdo->rollback(),否则连接销毁时抛出 PDOException(PHP 7.4+)。
关键区别点:
-
mysqli允许你在autocommit=0下执行多条语句后不commit就关闭连接——静默丢弃,无提示 - PDO 在
autocommit=0且未提交/回滚就销毁连接时,会触发致命错误或异常(取决于错误模式),更容易暴露遗漏 - 两者都不支持在同一个连接里混用
autocommit=1和autocommit=0的事务逻辑——切换会立即提交当前事务
事务的边界比看起来更脆。一个没捕获的异常、一次忘记 commit 的函数返回、甚至 ORM 框架里某个中间件悄悄调用了 SELECT @@autocommit,都可能让事务行为偏离预期。










