一文彻底读懂MySQL事务的四大隔离级别( 四 )

  • 如果 min_limit_id =<DB_TRX_ID<= max_limit_id,需要判断m_ids.contains(DB_TRX_ID),如果在,则代表Read View生成时刻,这个事务还在活跃,还没有Commit,你修改的数据,当前事务也是看不见的;如果不在,则说明,你这个事务在Read View生成之前就已经Commit了,修改的结果,当前事务是能看见的 。
  • 注意啦!! RR跟RC隔离级别,最大的区别就是:RC每次读取数据前都生成一个ReadView,而RR只在第一次读取数据时生成一个ReadView 。
    已提交读(READ COMMITTED) 存在不可重复读问题的分析历程我觉得理解一个新的知识点,最好的方法就是居于目前存在的问题/现象,去分析它的来龙去脉~ RC的实现也跟MVCC有关,RC是存在重复读并发问题的,所以我们来分析一波RC吧,先看一下执行流程
    一文彻底读懂MySQL事务的四大隔离级别

    文章插图
     
    假设现在系统里有A,B两个事务在执行,事务ID分别为100、200,并且假设存在的老数据,插入事务ID是50哈~
     
    事务A 先执行查询1的操作
    # 事务A,Transaction ID 100begin ;查询1:select *from account WHERE id = 1; 复制代码事务 B 执行更新操作,id =1记录的undo日志链如下
    begin;update account set balance =balance+20 where id =1;复制代码 
    一文彻底读懂MySQL事务的四大隔离级别

    文章插图
     
    回到事务A,执行查询2的操作
     
    begin ;查询1:select *from account WHERE id = 1; 查询2:select *from account WHERE id = 1; 复制代码查询2执行分析:
    • 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)在活跃,所以ReadView的m_ids列表内容就是[200]
    • 由上图undo日志链可得,最新版本的balance为1000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务A)不可见 。
    • 我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录200,所以这个版本可见,因此,查询2的结果,就是返回balance=100这个记录~~
    我们回到事务B,执行提交操作,这时候undo日志链不变
    begin;update account set balance =balance+20 where id =1;commit复制代码 
    一文彻底读懂MySQL事务的四大隔离级别

    文章插图
     
    再次回到事务A,执行查询3的操作
    begin ;查询1:select *from account WHERE id = 1; 查询2:select *from account WHERE id = 1; 查询3:select *from account WHERE id = 1; 复制代码查询3执行分析:
    • 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)已经提交,不载活跃,所以ReadView的m_ids列表内容就是空的了 。
    • 所以事务A直接读取最新纪录,读取到balance =120这个版本的数据 。
    所以,这就是RC存在不可重复读问题的过程啦~有不理解的地方可以多读几遍哈~
    可重复读(Repeatable Read)解决不可重复读问题的一次分析我们再来分析一波,RR隔离级别是如何解决不可重复读并发问题的吧~
    你可能会觉得两个并发事务的例子太简单了,好的!我们现在来点刺激的,开启三个事务~
    一文彻底读懂MySQL事务的四大隔离级别

    文章插图
     
    【一文彻底读懂MySQL事务的四大隔离级别】假设现在系统里有A,B,C两个事务在执行,事务ID分别为100、200,300,存量数据插入的事务ID是50~
     
    # 事务A,Transaction ID 100begin ;UPDATE account SET balance = 1000WHERE id = 1;复制代码# 事务B,Transaction ID 200begin ; //开个事务,占坑先复制代码这时候,account表中,id =1记录的undo日志链如下:
    一文彻底读懂MySQL事务的四大隔离级别

    文章插图
     
    # 事务C,Transaction ID 300begin ;//查询1:select * fromaccount WHERE id = 1;复制代码查询1执行过程分析:
    • 事务C在执行SELECT语句时,会先生成一个ReadView 。因为事务A(100)、B(200)在活跃,所以ReadView的m_ids列表内容就是[100, 200] 。
    • 由上图undo日志链可得,最新版本的balance为1000,它的事务ID为100,在活跃事务列表里,所以当前事务(事务C)不可见 。
    • 我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录100,所以这个版本可见,因此,查询1的结果,就是返回balance=100这个记录~~
    接着,我们把事务A提交一下:


    推荐阅读