mysql的acid需innodb引擎+显式事务+合理配置共同实现;autocommit=1时无事务边界;savepoint支持部分回滚;rr与rc在mvcc和锁机制上差异显著;混用myisam会破坏acid。

MySQL 的 ACID 特性不是靠「开启事务」就自动生效的
ACID(原子性、一致性、隔离性、持久性)在 MySQL 中并非全局默认保障,而是依赖存储引擎 + 显式事务控制 + 合理配置共同实现。InnoDB 是唯一在 MySQL 8.0+ 中完整支持 ACID 的内置引擎,但即使用了 InnoDB,AUTOCOMMIT=1 下每个语句仍是独立事务——这意味着 UPDATE 和 INSERT 分开执行时,中途失败无法回滚前一步。
关键判断:如果你没显式写 BEGIN / START TRANSACTION,也没关掉 AUTOCOMMIT,那实际上没有事务边界,也就谈不上 ACID。
-
SET AUTOCOMMIT = 0后必须配对COMMIT或ROLLBACK,否则连接断开时可能被自动回滚(取决于客户端行为) - InnoDB 的一致性(Consistency)不等于应用层业务逻辑一致,它只保证约束(如外键、唯一索引、CHECK)不被破坏;业务规则(如“余额不能为负”)需靠应用层或触发器兜底
- 崩溃恢复依赖
innodb_log_file_size和sync_binlog配置,sync_binlog=1+innodb_flush_log_at_trx_commit=1才能真正满足 D(Durability),但会明显影响写性能
如何用 SAVEPOINT 实现部分回滚而不破坏整个事务
SAVEPOINT 是 InnoDB 支持的轻量级回滚锚点,适用于嵌套逻辑中某步失败但想保留之前操作的场景(比如批量导入时跳过单条脏数据)。
注意:它不是子事务,不能提交,只用于 ROLLBACK TO SAVEPOINT;且同一个事务内同名 SAVEPOINT 会被覆盖。
START TRANSACTION; INSERT INTO orders VALUES (1001, 'A'); SAVEPOINT sp1; INSERT INTO order_items VALUES (2001, 1001, 'book', -5); -- 假设这里违反 CHECK(price > 0) ROLLBACK TO SAVEPOINT sp1; INSERT INTO order_items VALUES (2002, 1001, 'book', 29.9); COMMIT;
- 一旦执行
RELEASE SAVEPOINT sp1,该保存点即失效,后续ROLLBACK TO sp1会报错ERROR 1305 (42000): SAVEPOINT sp1 does not exist - 如果事务中发生死锁,MySQL 会自动选择一个事务回滚(通常是工作量小的那个),此时所有
SAVEPOINT都失效,整个事务结束 -
SAVEPOINT不释放行锁,回滚到它只是撤销逻辑变更,对应行记录的next_key_lock仍持有直到COMMIT或最终ROLLBACK
READ COMMITTED 和 REPEATABLE READ 隔离级别的实际差异在哪
InnoDB 默认是 REPEATABLE READ,但它和标准 SQL 定义不同:通过多版本并发控制(MVCC)+ Next-Key Lock 实现可重复读,**并不阻止幻读的语义问题**(只是用间隙锁让 INSERT 被阻塞,掩盖了现象);而 READ COMMITTED 每次 SELECT 都新建一致性视图,允许非阻塞的幻读。
真实影响体现在并发更新场景:
-- 会话 A(RR) START TRANSACTION; SELECT balance FROM accounts WHERE id = 1; -- 返回 100 -- 会话 B 提交:UPDATE accounts SET balance = 150 WHERE id = 1; -- 会话 A 再查,还是 100(MVCC 快照) <p>-- 会话 A(RC) START TRANSACTION; SELECT balance FROM accounts WHERE id = 1; -- 返回 100 -- 会话 B 提交:UPDATE accounts SET balance = 150 WHERE id = 1; SELECT balance FROM accounts WHERE id = 1; -- 返回 150(新快照)</p>
-
REPEATABLE READ下,范围查询(如SELECT ... WHERE age BETWEEN 20 AND 30)会加 Next-Key Lock,可能锁住不存在的间隙,导致并发插入被阻塞;READ COMMITTED只加行锁,不锁间隙 - 高并发统计类应用(如实时报表)用
READ COMMITTED更少锁冲突,但要注意两次查询结果可能不一致 - 切换隔离级别后,已开启的事务仍沿用原级别,新事务才生效;可通过
SELECT @@transaction_isolation确认当前会话值
事务超时后连接没断,但数据已经不可控了
InnoDB 本身没有事务级超时机制,wait_timeout 和 interactive_timeout 控制的是空闲连接生命周期,跟事务执行时长无关。真正影响事务执行的是 innodb_lock_wait_timeout(默认 50 秒)——它只管「等锁」超时,不管 SQL 执行慢。
常见误判:看到 Lock wait timeout exceeded 就以为是事务太久,其实往往是死锁检测失败或锁粒度不合理。
- 长时间运行的事务(如跑数脚本)会拖慢 MVCC 清理,导致
purge线程滞后,INFORMATION_SCHEMA.INNODB_TRX中trx_started时间过老,trx_mysql_thread_id对应线程可能还在 sleep - 用
KILL QUERY thread_id只中断当前语句,事务仍活跃;必须用KILL CONNECTION thread_id才强制回滚整个事务(但有风险:可能丢日志) - 应用层应设置语句级超时(如 JDBC 的
setQueryTimeout()),比依赖 MySQL 内置参数更可控
最易被忽略的一点:事务中混用 InnoDB 和 MyISAM 表,MyISAM 不支持事务,COMMIT 不会提交它,ROLLBACK 也无法回滚它——这种混合操作会让 ACID 彻底失效,且错误静默无提示。











