- 隔离级别+MVCC 实现读隔离性;
- 锁机制实现写隔离;
写隔离
MySQL 利用锁机制保护并发访问资源,实现写隔离。
根据保护的资源分类有如下锁:
latch(闩锁):rwlock、mutex,主要保护内存资源;
MDL: Metadata_lock,元数据(DDL 操作);
table_lock: 表级别
lock table t1 read ;
mysqldump、XBK(PBK):备份非InnoDB数据时,触发FTWRL全局锁表(Global)。
行锁升级为表锁。
row lock:InnoDB 默认锁粒度,加锁方式都是在索引加锁的。
record lock : 记录锁,在聚簇索引锁定。RC 级别只有 record lock。
gap lock : 间隙锁,在辅助索引间隙加锁。RR 级别存在。防止幻读。
next lock : 下一键锁,GAP+Record。RR 级别存在。防止幻读。
什么是幻读,RR 又是如何防止幻读?
幻读:在当前事务读到了另一个事务 insert
的数据。
解决:
- 如果查询条件为表的辅助索引,将会锁定辅助索引的查询范围,添加 gap lock,并且此范围中的每个聚簇索引上添加上 record lock,保证此范围内的行都不会有写入,此两种 lock 的组合为 next lock。
- 如果查询条件为表的聚簇索引,将会在查询范围的聚簇索引中添加上 record lock,仅保证对应聚簇索引的行不会被写入。
- 如果查询条件不是表的索引,将会全表扫描,即原本的行锁会升级为表锁。
功能性上可分为:
IS : select * from t1 lock in shared mode;
S : 读锁。
IX : 意向排他锁。表上添加的。 select * from t1 for update;
X : 排他锁,写锁。
读隔离
MySQL 利用 MVCC + 隔离级别
实现读隔离。
隔离级别的读隔离:
- RU : 脏读 、 不可重复读 、幻读
- RC : 不可重复读、幻读
- RR :有可能会出现幻读。
- SR(SE) :事务串行工作,完全隔离。
MVCC利用乐观锁机制,实现非锁定读取。
做每一个查询操作时,会在当前事务获取到系统最新的快照,此处被称为 read view。
read view:RV,版本号集合。
每个事务后续的查询都基于当前事务中最新的快照进行查询,而不去找原表数据,所以实现了读的隔离。
Read view 在 RC 和 RR 隔离级别下的生成规则有所不同。
RC 级别下每个查询操作就会生成一个新的 read view,当前事务也能读取到其它事务 commit 的 read view,后续的查询都是基于前最新的 read view。
RR 级别下从第一个查询开始就生成一个 global consistence snapshot read view,该 read view 一直伴随着事务生命周期的结束,这也是 RR 隔离级别下支持可重复读的一个原因。
快照技术由 undo log 来提供。
总结:
- MVCC采用乐观锁机制,实现非锁定读取。
- 在 RC 级别下,事务中可以立即读取到其他事务 commit 过的readview。
- 在 RR 级别下,事务中从第一次查询开始,生成一个一致性 readview,直到事务结束。