MySQL 的存储引擎不是可有可无的插件,而是直接决定你能不能用事务、数据会不会丢、并发读写是否安全的核心组件。选错引擎,
InnoDB和
MyISAM表混用,或者误以为“开了事务就一定原子”,都是线上事故常见起点。
为什么 InnoDB
是默认且几乎唯一推荐的事务引擎
InnoDB是 MySQL 5.5+ 默认引擎,它把索引和数据一起存(聚簇索引),支持行级锁、MVCC、外键和完整的 ACID 实现。而
MyISAM只支持表级锁、无事务、崩溃后容易坏表——哪怕只是断电,也可能丢失最后几条
INSERT的数据。
MyISAM的
AUTO_INCREMENT是表级缓存,高并发插入可能卡住;
InnoDB是行级 + 意向锁,冲突更少
InnoDB的
REPLACE INTO或
INSERT ... ON DUPLICATE KEY UPDATE能安全处理重复键,
MyISAM在此场景下可能触发非预期的删除+插入顺序 即使只读场景,也别迷信
MyISAM更快:现代 SSD + 缓存下,
InnoDB的随机读性能差距极小,且避免了修复表(
REPAIR TABLE)这种运维黑洞
BEGIN
/ START TRANSACTION
后,什么才算真正开启一个事务
事务不是靠语句开头几个字就生效的,它受
autocommit状态和存储引擎双重约束。执行
BEGIN本身不启动事务,只是把当前会话的
autocommit设为 0;如果连的表是
MyISAM,哪怕写了
COMMIT,也不会回滚任何东西。 检查当前事务状态:
SELECT @@autocommit, @@in_transaction;
SET autocommit = 0后所有 DML 都进入隐式事务,直到显式
COMMIT或
ROLLBACK;但 DDL(如
ALTER TABLE)仍会自动提交,无法回滚 长事务(>10 秒)会拖慢 purge 线程,导致
ibdata1文件持续膨胀、历史版本链过长,最终拖垮查询性能
ACID 里最容易被误解的是 “I”(隔离性)和 “D”(持久性)
ACID 不是开关,而是由引擎实现 + 隔离级别 + 刷盘策略共同决定的行为边界。
READ COMMITTED下不会出现脏读,但幻读依然存在;
innodb_flush_log_at_trx_commit=1才保证事务提交后日志落盘,否则断电可能丢最近 1 秒的已提交事务。
REPEATABLE READ是
InnoDB默认级别,靠 MVCC + next-key lock 解决幻读,但仅限当前读(
SELECT ... FOR UPDATE);快照读(普通
SELECT)看到的是事务开始时的一致视图
innodb_doublewrite=ON必须开着——它防止页写入一半崩溃导致数据页损坏,关掉等于拿一致性换一点点写入延迟
sync_binlog=1和
innodb_flush_log_at_trx_commit=1配合,才能在主从切换时保障 binlog 和 redo log 严格一致,否则可能丢事务或主从不一致
真正难的不是记住 ACID 定义,而是当
SELECT突然变慢、
UPDATE开始锁表、或者从库延迟飙升时,能快速判断是隔离级别副作用、刷盘参数松动,还是引擎本身不支撑这个业务模型。
