关于后端:MVCC并发管理控制

39次阅读

共计 2284 个字符,预计需要花费 6 分钟才能阅读完成。

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 判断版本链上的版本对事务的可见性
  1. 如果版本链上的版本的 trx_id 与 readView 上的 creator_trx_id雷同,阐明以后事务是在拜访本人批改过的记录。
  2. 如果版本链上的版本的 trx_id小于readView 上的 min_trx_id,阐明此版本曾经提交,具备可见性。
  3. 如果版本链上的版本的 trx_id大于readView 上的 max_trx_id, 阐明此版本是产生在 readView 之后,不具备可见性。
  4. 如果被拜访版本的 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 多平台公布

正文完
 0