MVCC 并发管理控制
并发带来的读写问题
因为 mysql 是 cs 构造,一台服务端能够对接多个客户端,那必然就会存在多个线程对同一资源(同一条记录之类的)进行 读读,读写,写写 操作。
<font size= 4> 脏写:一个事务批改了其余事务未提交的数据。</font>
<font size= 4> 脏读:一个事务读到了其余事务未提交的数据。</font>
<font size= 4> 不可反复读:A 事务先依据肯定条件查问记录,而后 B 事务批改了其中的数据,A 事务再次依据雷同的条件查问记录,发现和之前的相比数据值变了。(突出批改)</font>
<font size= 4> 幻读:A 事务先依据肯定条件查问出记录, 而后 B 事务增加或删除些数据,A 事务再次依据雷同的查问条件查问记录,发现比之前的数据多了或少了。(突出删除和减少)</font>
事务隔离级别解决了什么
为了解决并发读写呈现的问题,设计者们就打算损失一些隔离性来防止这些问题
读未提交
读已提交
可反复读
串行化
<font color= red> 设立一些隔离级别,隔离级别越低,越重大的问题就越可能产生 </font>
串行化性能损失最重大,因为他保障了线程对同一资源批改,只能串行批改。
设置事务隔离级别
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;
level 有四个
- READ UNCOMMITTED(读取最新数据)
- READ COMMITTED(读取已提交数据,须要用到 mvcc)
- REPEATABLE READ(不可反复读,须要用到 mvcc)
- SERIALIZABLE(串行化,间接加锁)
MVCC 并发管理控制由来
mysql 为什么要须要 mvcc
因为并发带来的数据拜访问题,解决数据拜访问题,同时又要兼顾效率,不能一味的锁住,像 RC 和 RR 是须要靠 mvcc 机制实现的。
像提到 MVCC 就必须要理解下 以后读和快照读的概念了
- 以后读:读取最新的数据,可能会对数据产生影响,像 select xxx for update,insert ,delete,update,都会触发以后读,可反复读应用以后读时,mvcc 机制就不能用了,须要应用行锁(临建锁 = 记录锁 + 间隙锁)保障其隔离作用。
- 快照读:利用了 mvcc 机制,读取某个版本数据信息,是的整个事务数据前后是统一的,但无奈保证数据是最新的。像个别的 select 用的就是以后读
版本链
对于 InnoDB 数据引擎来说,聚簇索引的每条记录都会有两个暗藏列
trx_id: 每次一个事务对某条聚簇索引记录进行改变时,都会把该事务的 事务 id 赋值给 trx_id 暗藏列
roll_pointer: 回滚指针,指向旧记录(undo log)
此时事务 id 为 100, 和 200 开始进行更新操作
每次更新记录,对应记录的 undo log 就会多一条 像上面这样
随着批改次数增多,undo log 会被 roll_pointers 属性连成一个单向链表,<font color= red> 咱们把这个链表称之为 版本链,版本链的头节点就是以后记录最新的值 </font>
readView(读视图)
- 对于【读未提交】,只须要读最新的记录就好,都不须要用到版本链。
- 对于【串行化】,因为他的隔离级别最高,是并发变成串行,不会存在并发问题,只是效率变低了,所以也不须要用到版本链。
- 对【读已提交】,【可反复读】,<font color= red> 都须要保障不能读到其余事务未提交的数据 </font>, 所以就须要判断下,版本链上的哪个版本是对以后事务具备可见性,这个就须要 readView 啦
readView 构造
- m_ids: 示意生成 readView 的时候,以后未提交的事务 id.
- min_trx_id: 示意生成 readView 的时候,未提交的事务中事务 id 最小的那个。
- max_trx_id: 示意生成 readView 的时候,应该调配下一个事务的 id。
- creator_trx_id: 示意生成该 ReadView 的事务的 事务 id。
咱们前边说过,只有在对表中的记录做改变时(执行 INSERT、DELETE、UPDATE 这些语句时)才会为事务调配事务 id,否则在一个只读事务中的事务 id 值都默认为 0。
依据 readView 判断版本链上的版本对事务的可见性
- 如果版本链上的版本的 trx_id 与 readView 上的 creator_trx_id雷同,阐明以后事务是在拜访本人批改过的记录。
- 如果版本链上的版本的 trx_id小于readView 上的 min_trx_id,阐明此版本曾经提交,具备可见性。
- 如果版本链上的版本的 trx_id大于readView 上的 max_trx_id, 阐明此版本是产生在 readView 之后,不具备可见性。
- 如果被拜访版本的 trx_id 属性值在 ReadView 的 min_trx_id 和 max_trx_id 之间,那就须要判断一下 trx_id 属性值是不是在 m_ids 列表中,如果在,阐明创立 ReadView 时生成该版本的事务还是沉闷的,该版本不能够被拜访;如果不在,阐明创立 ReadView 时生成该版本的事务曾经被提交,该版本能够被拜访。
read Committed 与 repeatable read 的 readView 生成机会
- 【read committed】是事务中,每查问一次就生成一次 readView
- 【repeatable read】是事务中,第一次查问生成 readView,之后就不生成了。
总结一句:看版本链上的版本是否早于 readView 提交,早于的话,阐明曾经提交事务,具备可见性,如果晚于的话,阐明该版本还是未提交的,不具备可见性。
原创不易,麻烦点个赞再走呗!
本文由 mdnice 多平台公布