mysql事务需先关闭autocommit=1(set autocommit = 0),再用start transaction显式开启,否则update/delete立即生效无法回滚;start transaction支持read only、read write等修饰符提升安全性和可读性。

MySQL事务不是“开了就能保安全”的开关,而是需要明确控制边界、理解提交时机、避开自动提交陷阱的一整套协作机制。不显式管理,BEGIN 和 COMMIT 就等于没开。
为什么 UPDATE/DELETE 没生效?大概率是 autocommit 没关
MySQL 默认开启 autocommit=1,意味着每条 UPDATE、INSERT、DELETE 都是独立事务,执行完立刻落盘——你根本没机会 ROLLBACK。想手动控制,必须先关掉它:
- 会话级关闭(推荐):
SET autocommit = 0;,只影响当前连接,断开即恢复默认 - 别用
SET GLOBAL autocommit = 0;,会影响所有新连接,极易引发线上事故 - 验证是否生效:
SELECT @@autocommit;返回0才算成功
关了之后,再执行 BEGIN 或 START TRANSACTION 才真正进入可回滚的事务上下文。
START TRANSACTION 后加修饰符能省掉不少坑
START TRANSACTION 比 BEGIN 多一个关键能力:支持修饰符,直接声明事务意图,避免误操作。
-
START TRANSACTION READ ONLY;:禁止任何写操作(INSERT/UPDATE/DELETE),连DROP TEMPORARY TABLE都不行,但允许建/删临时表——适合报表类只读查询 -
START TRANSACTION READ WRITE;:显式声明可读写(也是默认行为),建议加上,让逻辑更自解释 -
START TRANSACTION WITH CONSISTENT SNAPSHOT;:强制开启一致性读,对长事务或高并发场景很关键,避免被其他事务的中间状态干扰
注意:READ ONLY 不限制对临时表的操作,因为临时表只在当前会话可见,不参与 MVCC 快照竞争。
事务里改数据,锁和性能要提前想清楚
事务不是魔法盒,UPDATE 或 DELETE 在事务中照样会加锁,且锁持续到 COMMIT 或 ROLLBACK。常见踩坑点:
- 没走索引的
WHERE条件 → 触发表级锁或大量行锁 → 其他事务卡住 - 大范围更新(如
UPDATE users SET status = 1 WHERE created_at )→ 锁住成千上万行 → <code>ROLLBACK耗时飙升,甚至触发lock_wait_timeout - 事务里混用 DDL(如
ALTER TABLE)→ 自动触发隐式COMMIT→ 后续语句脱离事务控制,无法回滚
实操建议:先用 SELECT ... FOR UPDATE 预估锁范围;大更新拆成小批量(比如每次 1000 行 + WHERE id BETWEEN ? AND ?);DDL 操作单独执行,别塞进业务事务。
COMMIT 失败 ≠ 数据没变,ROLLBACK 也可能失败
COMMIT 看似简单,但背后涉及 redo log 刷盘、binlog 写入、两阶段提交等多个环节。一旦失败,可能已部分落盘。
-
COMMIT报错(如磁盘满、网络中断)→ 状态不确定,需查SHOW ENGINE INNODB STATUS中的TRANSACTIONS部分确认是否已提交 -
ROLLBACK耗时长 → 说明 undo log 很大,可能是事务太久或修改太多行,别强行 kill,等它自己完成,否则可能损坏 rollback segment - 不要依赖客户端提示“Query OK”就认为成功——网络断开时,客户端可能收不到响应,但服务端已提交
最稳妥的做法:关键业务事务后,用一条带校验的 SELECT 确认结果,而不是只信返回码。











