标签:code 依次 read 节点 空间 false 语句 zab rem
每个客户端和服务器的一次连接,就是一个会话,而每个客户端可以在自己的会话中发出事务请求,一般来说一个服务器可以连接若干个客户端,所以一个服务器可以同时处理很多事务请求,但理论上某个事务在对某个数据在进行访问时,其他事务应该排队等待。但这样在高并发下会严重影响性能,所以只能设计事务隔离级别来兼顾事务的隔离性和提高多个事务的性能。
如果事务执行不保证串行执行,也就是并发执行会遇到以下几个问题:
根据这几个问题,SQL标准设计了4个隔离级别,在不同程度上禁止了这些问题的发生。
READ UNCOMMITTED
隔离级别下,可能发生脏读
、不可重复读
和幻读
问题。READ COMMITTED
隔离级别下,可能发生不可重复读
和幻读
问题,但是不可以发生脏读
问题。REPEATABLE READ
隔离级别下,可能发生幻读
问题(MySQL下会禁止),但是不可以发生脏读
和不可重复读
的问题。SERIALIZABLE
隔离级别下,各种问题都不可以发生。InnoDB使用锁来保证脏写的情况不会发生。
解决脏读,不可重复读,幻读可以采用两种方法:
读操作利用MVCC,写操作加锁(读-写事务不冲突)
读写操作都加锁(读-写事务需要排队执行)
(Multi-Version Concurrency Control ,多版本并发控制),MVCC指的就是在使用指的就是在使用READ COMMITTD
、REPEATABLE READ
这两种隔离级别的事务在执行普通的SEELCT
操作时访问记录的版本链的过程,这样子可以使不同事务的读-写
、写-读
操作并发执行,从而提升系统性能。而剩下两种隔离级别执行普通select操作时的区别就是生成ReadView的时机不同;事务利用MVCC进行的读操作也被称为一致性读/一致性无锁读/快照读
每条记录在插入时都会隐式的生成两个列:trix_id,roll_pointer,trix_id是它最新的事务id,在记录每次更新时,就会将旧值写入undo日志,并将roll_pointer指向它;每条undo日志也有自己roll_pointer属性和事务id属性,所以可以将这些记录根据roll_pointer串成一条链表(版本链),版本链的头节点就是当前记录的最新值
READ UNCOMMITTED隔离级别的事务只需要读取版本链中最新的记录就可以了,不需要管它是否已经被提交
READ COMMITTED,REPEATABLE READ隔离级别的事务都是基于已提交的事务的,所以需要判断版本链中哪个版本是 对当前事务可见的,所以InnoDB中使用ReadView方式来判断。
ReadView由事务生成时创建
如何判断记录的某个版本是否对当前事务可见,如果不可见,就需要沿着版本链一直向下比较
每次读取数据前都生成一个独立的ReadView,这样根据版本链依次判断,然后将可见的那个版本返回回去。
只在第一次读取数据时生成一个ReadView,后面的select重复使用一个ReadView
SERIALIZABLE隔离级别的事务需要加锁来访问记录
共享锁Shared Locks
//对读取加s锁
SELECT ... LOCK IN SHARE MODE;
独占锁Exclusive Locks
定位某条需要修改/删除记录在B+树位置后,再获取一下记录的x锁,其实就是一个获取x锁的锁定读
//对读取加x锁
SELECT ... FOR UPDATE;
s锁和x锁是互斥的,s锁和s锁不互斥,x锁和x锁互斥
多粒度锁
表级锁
意向共享锁IS/意向独占锁IX
表中某列带有AUTO_INCREMENT属性
AUTO-INC锁(适用于不确定数量的插入insert....select)
在执行一个插入语句时就在表级别加一个AUTO-INC锁,然后为每个需要自增的列生成值,在语句执行结束后,就释放锁;在这个锁被持有的过程中,其他需要插入的语句是被阻塞的
轻量级的锁(适用于确定记录的插入)
在执行一个插入语句时获取这个轻量级锁,然后为每个需要自增的列生成值后,就释放锁;在这个锁被持有的过程中,其他需要插入的语句是被阻塞的
行级锁
符合下列条件的记录集,就会将它们的锁放到一个锁结构中,减少一条记录一个锁占用的空间
锁所在的事务信息:指向生成这个锁结构的事务信息
索引信息:指向记录加锁的记录属于哪个索引(聚簇索引)
表锁/行锁信息:
type_mode
标签:code 依次 read 节点 空间 false 语句 zab rem
原文地址:https://www.cnblogs.com/hangzhi/p/11427540.html