跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

mysql不同隔离级别解决了哪些问题_mysql事务现象解析

脏读在 READ UNCOMMITTED 下一定会发生,因为该隔离级别完全不加读锁也不检查写锁,SELECT 可直接读到其他事务未 COMMIT 的修改,如事务 A 更新某行未提交,事务 B 此时 SELECT 即可读到脏值。 脏读在 READ UNCOMMITTED 下为什么一定会发生 因为该隔离级别完全不加读锁,也不检查写锁,
SELECT
可以直接读到其他事务尚未
COMMIT
的修改。比如事务 A 更新了某行但未提交,事务 B 此时执行
SELECT
就能拿到这个“脏值”。 常见错误现象:
ERROR 1205 (40001): Deadlock found when trying to get lock
虽然不直接相关,但很多人误以为开低隔离级就能避免死锁——其实相反,
READ UNCOMMITTED
会放大并发写冲突的隐蔽性。 实操建议: 仅用于日志表、监控计数等允许误差的只读场景 MySQL 默认不启用此级别,需显式设置
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
ORM 框架(如 Django、MyBatis)通常不支持该级别,强行配置可能被忽略 不可重复读和幻读的区别到底在哪 不可重复读(Non-Repeatable Read)指同一事务中两次
SELECT
同一行,结果不一致,原因是其他事务对该行执行了
UPDATE
或
DELETE
并已提交;而幻读(Phantom Read)是两次
SELECT
返回行数不同,原因是其他事务插入(
INSERT
)或删除了满足条件的新行。 关键区别在于:不可重复读聚焦「已有行内容变化」,幻读聚焦「结果集范围变化」。 MySQL InnoDB 在
REPEATABLE READ
级别下通过间隙锁(Gap Lock)+ 行锁(Record Lock)阻止幻读,但仅对当前读(如
SELECT ... FOR UPDATE
、
SELECT ... LOCK IN SHARE MODE
)生效;快照读(普通
SELECT
)靠 MVCC 避免不可重复读,但本身不解决幻读——只是你“看不见”新插入的行。 实操建议:
SELECT * FROM t WHERE id = 1
是快照读,不会阻塞插入;但
SELECT * FROM t WHERE id = 1 FOR UPDATE
会加临键锁(Next-Key Lock),阻止间隙插入 用
EXPLAIN
查看执行计划时,若出现
type: index
且
Extra: Using where; Using index
,说明走了覆盖索引,但间隙锁范围仍由查询条件决定,不是由是否覆盖决定 唯一索引等值查询(如
WHERE id = ?
)只锁匹配行,不锁间隙;普通索引或范围查询才触发间隙锁 为什么 MySQL 默认用 REPEATABLE READ 而不是 READ COMMITTED 历史原因:早期 MySQL 主从复制依赖语句级(SBR)模式,
READ COMMITTED
下同一事务内多次执行相同语句可能产生不同结果,导致主从不一致;虽然现在默认是行级复制(RBR),但兼容性与行为稳定性让
REPEATABLE READ
保留为默认。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 性能影响明显:
REPEATABLE READ
需维护更长的 undo log 链(事务开启后第一个快照持续有效),高并发长事务容易撑爆
undo tablespace
;而
READ COMMITTED
每次快照读都取最新已提交版本,undo 压力小。 实操建议: 高并发短事务(如 API 请求)可考虑全局设为
READ COMMITTED
,降低锁竞争和 undo 开销 变更隔离级别前务必测试 binlog 格式:
SHOW VARIABLES LIKE 'binlog_format'
应为
ROW
,否则 SBR +
READ COMMITTED
仍有风险 Spring
@Transactional(isolation = Isolation.READ_COMMITTED)
在 MySQL 上生效,但要注意连接池是否复用旧连接并携带旧隔离级 Serializable 怎么“彻底”解决所有并发问题
SERIALIZABLE
会让所有普通
SELECT
自动转成
SELECT ... LOCK IN SHARE MODE
,即每次读都加共享锁,写操作则需排他锁,本质上把并发事务串行化执行。 这确实消灭了脏读、不可重复读、幻读,但也带来严重代价:并发度归零倾向,极易触发锁等待甚至死锁。例如两个事务同时执行
SELECT * FROM t WHERE status = 0
,再各自尝试
UPDATE
其中某行,就会因共享锁互斥而卡住。 实操建议: 不要在业务代码里动态设为
SERIALIZABLE
,它更适合离线数据校验脚本或极低频管理后台操作 若真需要强一致性,优先考虑应用层加分布式锁(如 Redis SETNX)或用乐观锁(
version
字段 +
WHERE version = ?
)替代
SHOW ENGINE INNODB STATUS\G
中的
TRANSACTIONS
段会显示当前持有哪些锁,
SERIALIZABLE
下很容易看到大量
LOCK_MODE: S
和
LOCK_TYPE: RECORD
条目 事务隔离级别的选择从来不是“越严越好”,而是权衡一致性需求、性能损耗和锁行为复杂度。最容易被忽略的是:MVCC 快照读的可见性规则与锁机制是两套并行逻辑,混用时(比如一边快照读、一边
FOR UPDATE
)容易误判“为什么没锁住”。

相关文章