mysql事务可重读技术实现学习摘要

database

MySQL中有4个事务隔离级别

MySQL中有4个事务隔离级别:读未提交,读已提交,可重复读和串行化。 事务的四大特性ACID(Atomicity原子性、Consistency一致性、Isolation隔离性、Durability持久性。 隔离级别的设定为数据库服务器的并发,可靠性和性能之间提供了选择。隔离级别越高,性能越低,ACID的完成度越高。 而不同的级别设定,一般带来如下图所列的问题:

可重复读的技术实现

MVCC

Mysql mvcc行更新过程: https://yq.aliyun.com/articles/283418?spm=a2c4e.11153940.0.0.4b3224eb4hoiqb。

重点: 每个事务做update的时候,copy原始数据到undo log中,然后会修改DB_TRX_ID为当前事务ID,及修改数据本身,如果存在更老版本的数据会更新回滚指针DB_ROLL_PTR。 MVCC只解决了阻塞读的问题,事务以排他锁的形式修改原始数据。

Innodb的实现真算不上MVCC ,因为并没有实现核心的多版本共存,undo log中的内容只是串行化的结果,记录了多个事务的过程,不属于多版本共存。但理想的MVCC是难以实现的,当事务仅修改一行记录使用理想的MVCC模式是没有问题的,可以通过比较版本号进行回滚;但当事务影响到多行数据时,理想的MVCC据无能为力了。 多行数据修改时, 会遇到2pc相同的问题。多行数据的情况下, 会遇到部分失败下,无法完美回滚。

Read View

read view其实就是一个保存事务ID的list列表。记录的是本事务执行时,MySQL还有哪些事务在执行。readview是记录的当前活跃的事务列表。 因为undo log链表中,存在过时的事务log, 需要等待purge线程定期清理。 而readview可以快速响应用户的read request,副本中保存的是系统当前不应该被本事务看到的其他事务id列表。当用户在这个事务中要读取该行记录的时候,innodb就会从根据 read view,来决定是读取该行记录的当前版本,还是需要从undo-log中去寻找更早的版本。 大致过程是: 根据readview中up_id 和low_id判断,如cur_id>up_id,可以读取, cur_id<low_id则不可见。在读提交级别的事务中,会更复杂里面,多一些判断。

  • Read Repeatable对应的是在每个事务启动的时候创建 一个Read View。每个事务生成一个read view。
  • Read Commit对应的是每次执行SQL statement时候创建。 每条只读语句生成一个Read View。
  • Read view创建之后,读数据时比较记录最后更新的trx_id和view的high/low water mark和读写事务数组即可判断可见性。

回滚段

(之前网上摘抄部分博客, 没记录原文地址. 原作者看到有问题联系我)

在undo log中记录的老版本的数据。 但一个长事务,需要读取老版本的数据时,需要顺着undo log链表找到老版本的数据。(查找条件是什么?DB_ROLL_PTR指针进入到undo log 的链表中) undo log存储在ibdata表空间中,或者独立的undo tablespace中。

  • Undo log <— undo slot. 每个回滚段的段头页中维护1024个slot。 因此mysql默认支持96 * 1024个普通事务。
  • 记录的DB_ROLL_PTR指向最近一次更新所创建的回滚段;每条undo log也会指向更早版本的undo log,从而形成一条更新链。通过这个更新链,不同事务可以找到其对应版本的undo log,组成old version记录,这条链就是记录的history list。
  • 在innodb中,创建一个新事务的时候,innodb会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。当用户在这个事务中要读取该行记录的时候,innodb会将该行当前的版本号与该read view进行比较。

    具体的算法如下:

  1. 设该行的当前事务id为trx_id_0,read view中最早的事务id为trx_id_1, 最迟的事务id为trx_id_2。
  2. 如果trx_id_0< trx_id_1的话,那么表明该行记录所在的事务已经在本次新事务创建之前就提交了,所以该行记录的当前值是可见的。跳到步骤6.
  3. 如果trx_id_0>trx_id_2的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见.跳到步骤5。
  4. 如果trx_id_1<=trx_id_0<=trx_id_2, 那么表明该行记录所在事务在本次新事务创建的时候处于活动状态,从trx_id_1到trx_id_2进行遍历,如果trx_id_0等于他们之中的某个事务id的话,那么不可见。跳到步骤5.
  5. 从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号,将它赋值该trx_id_0,然后跳到步骤2.

大事务带来的影响

1.定义:运行时间比较长,操作的数据比较多的事务

2.大事务风险:

a)锁定太多的数据,造成大量的阻塞和锁超时,回滚所需要的时间比较长。

b)执行时间长,容易造成主从延迟

3.如何处理大事务

a)避免一次处理太多大数据

b)移出不必要在事务中的select操作

以上是 mysql事务可重读技术实现学习摘要 的全部内容, 来源链接: utcz.com/z/532640.html

回到顶部