并发控制
一. 事务隔离级别
二. 锁
2.1 全局锁
2.2 表级锁
共享锁(Read Lock)、独占锁(Write Lock)
语法
是针对非索引字段加的锁
加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。
表级锁和存储引擎无关,MyISAM 和 InnoDB 引擎都支持表级锁。
- 元数据锁
meta data lock。表级锁的一种。非手动控制,访问表时自动加上。
为了维护元数据(表结构)的数据一致性。
当进行dml(crud)操作时,自动加上读锁。
当进行ddl(表结构变更)操作时,自动加上排他锁。
- 意向锁
为了解决DML语句执行时,添加的行锁可能与表锁冲突的问题,引入意向锁,快速判断是否可以对某个表使用表锁。
分类:
意向共享锁IS:查询语句。兼容Read Lock表锁,互斥 Read Lock表锁。
意向排他锁IX:CRUD。与表锁都互斥。
意向锁之间不会互斥。
注意意向锁是行锁的伴生锁,是自动添加的。
2.3 行级别锁
锁的是数据行。
针对索引字段加的锁。自动添加。
当执行一个UPDATE或DELETE操作并且命中了索引(无论是唯一索引还是非唯一索引),InnoDB会尝试仅仅对满足条件的那些行加锁。对于非唯一索引,会对查询结果范围左侧的间隙和右侧的间隙加间隙锁(避免重复值的插入)
如果无有效索引:如果WHERE条件没有利用到有效的索引,那么InnoDB会执行全表扫描来找到需要更新或删除的行。在这个过程中,它会逐行加锁,直到完成全表扫描。尽管这些是行级锁,但由于它涉及到了整张表的所有行,所以实际上整个表在此期间都被锁定了。
分类:
-
行锁:对某条记录上锁,防止update和delete。RC、RR
-
间隙锁:对两条记录的间隙上锁。RR。防止insert。
-
临键锁:锁住数据并锁住数据前面的间隙。RR
三. MVCC
3.1 InnoDB逻辑存储结构
表空间(IDB文件):存储索引、记录等数据
3.2 InnoDB物理结构
InnoDB分为内存结构和磁盘结构。
3.2.1 内存结构
- Buffer Pool:批量将磁盘的数据预读进内存,再批量写回(减少IO)
- Change Buffer: 优化非聚簇索引的写入操作,实现批量写。减少IO次数
- 自适应哈希索引
原因:等值查询的速度更快
- 日志缓冲区
3.2.2 磁盘结构
3.2.3 后台线程
复制将内存信息刷到磁盘中
3.3 事务原理
原子性、持久性(Redo Log + Undo Log) + 隔离性(锁/MVCC) -> 实现了数据一致性
3.3.1 Undo Log
解决事务的原子性。
3.3.2 Redo Log
脏页是指还未来的及刷新到磁盘的buffer pool中的数据。Redo Log解决脏页通过IO刷到磁盘失败的问题(持久化)
此外,先刷redo log buffer还能提高性能。避免了随机IO。(Write-Ahead Log)等脏页刷进磁盘,则可以清理redo log。
补充 bin log
bin log是实现主从复制的核心,主服务器上的所有数据更改(在Binary Log中记录)会被复制到从服务器。从服务器读取这些日志并执行它们,从而使从服务器与主服务器保持同步。它是一个增量日志。
3.4 MVCC
MVCC用于非阻塞的解决读写冲突的问题(不可重复读)。
MVCC规定,Select语句读取快照(不一定是最新的数据)。update读的是当前(最新的)。
在可串行化隔离级别,快照读没有任何意义,会被升级未当前读。
正是MVCC的存在,MySQL在可重复读的隔离级别解决了幻读问题。
-
隐藏字段
-
row id.
-
trx_id: 最近的一次更新当前数据的事务id
-
回滚指针:
若干回滚指针连接起来,就组成了undo log。 -
ReadView
-
MVCC的执行流程
注意可重复读是要保证事务内的两个相同select读取结果相同