V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JasonLaw
V2EX  ›  数据库

MySQL 是这样实现可重复读的

  •  
  •   JasonLaw · 2020-07-05 17:55:49 +08:00 · 2732 次点击
    这是一个创建于 1595 天前的主题,其中的信息可能已经有所发展或是发生改变。
    13 条回复    2020-09-20 20:23:24 +08:00
    lhx2008
        1
    lhx2008  
       2020-07-05 18:29:07 +08:00 via Android
    mvcc 呢。。
    JasonLaw
        2
    JasonLaw  
    OP
       2020-07-05 18:59:57 +08:00 via iPhone
    @lhx2008 也许标题应该改一下😅,因为文章没有讲到 consistent nonlocking read,只是讲到了 locking read,虽然知道 MVCC 相关理论,但是不太了解 InnoDB 具体是怎么实现的。有空了解了之后再补充。
    zhangysh1995
        3
    zhangysh1995  
       2020-07-05 19:21:02 +08:00 via Android
    感谢分享,先收藏慢慢看。
    yeqizhang
        4
    yeqizhang  
       2020-07-05 20:44:12 +08:00 via Android
    刚想说头一次在手机上打开简书了,没想到给我跳转到云浏览器打开了……
    louettagfh
        5
    louettagfh  
       2020-07-05 22:37:39 +08:00   ❤️ 1
    你这个理解可能不太对

    可重复读是事务隔离级别

    你在文章里写的:

    因为 session 1 执行 select * from t where id = 5 for share 之后,会拥有表级别的共享意向锁和 id 为 5 的那个索引记录的共享锁,所以 session 2 虽然获取到了表级别的独占意向锁,但是它无法获取到 id 为 5 的那个索引记录的独占锁。任何事务都不能够修改或删除 id 为 5 那行,因此保证了可重复读。

    最后一句" 任何事务都不能够修改或删除 id 为 5 那行,因此保证了可重复读。" 这句表述的不对,一个事务可以有多条语句,s1 创建事务 t1 用 record lock 锁住了这条 record, 但它执行 t1 后面的语句时,这把 record lock 已经被放开了. 其他事务的是可以修改的 id 为 5 的 record.

    MySQL 如何实现可重复读?
    利用 MVCC

    在 MySQL 中 MVCC 是 undo log + read view,依然以你的例子举例:
    s1 创建事务 t1 时会创建 read view 即 r1,
    s2 创建事务 t2 时会创建 read view 即 r2.

    t1 第一次读 id=5 的 record 为 v1,
    t2 修改 id=5 的 record 为 v2,
    t1 再次读的时候会利用 read view 即 r1,判断 v2 是否可读,它会发现 v2 的 trx_no 大于 r1 的 trx_no, t1 就利用 undo log 回溯上一个版本即 v1. 这是可重复读.
    louettagfh
        6
    louettagfh  
       2020-07-05 22:42:47 +08:00
    接上条 漏了一点

    t2 修改 id=5 的 record 为 v2 后就提交 commit.
    UN2758
        7
    UN2758  
       2020-07-05 22:58:06 +08:00   ❤️ 1
    JasonLaw
        8
    JasonLaw  
    OP
       2020-07-05 23:28:27 +08:00
    @louettagfh

    1. 你说“一个事务可以有多条语句,s1 创建事务 t1 用 record lock 锁住了这条 record, 但它执行 t1 后面的语句时,这把 record lock 已经被放开了. 其他事务的是可以修改的 id 为 5 的 record.”,可以用实例展现一下吗?
    2. 你说“MySQL 如何实现可重复读? 利用 MVCC”,其实我讲的主要是 locking read 的可重复读,而不是 consistent nonlocking read 的可重复读,可以标题有点误导吧,我会修改一下。
    3. 你说创建事务时就创建 read view,这个应该不对吧?在 https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html 中,它说“If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction.”,“With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.”,不管是哪个级别,都不是创建事务时就去建立 snapshot 。
    JasonLaw
        9
    JasonLaw  
    OP
       2020-07-06 08:08:38 +08:00 via iPhone
    @UN2758 谢谢,明白了 InnoDB 具体是怎么实现的了。
    louettagfh
        10
    louettagfh  
       2020-07-06 09:58:02 +08:00
    @JasonLaw 第二个问题 你要纠结这个细节 不妨直接看源码 我们讨论的是可重复的隔离级别 我说的是事务创建时就创建 read view:

    mysql-server/blob/8.0/storage/innobase/handler/ha_innodb.cc#L5170

    5170 行是创建可重复读隔离级别的事务

    5190 行启动

    5199 行分配 read view
    JasonLaw
        11
    JasonLaw  
    OP
       2020-07-06 10:20:35 +08:00
    @louettagfh 我不是纠结细节,我只是想知道事情到底是怎样的。
    louettagfh
        12
    louettagfh  
       2020-07-12 16:12:19 +08:00
    @JasonLaw 那就直接看代码 看别人写的文档都是二手资料
    pythonee
        13
    pythonee  
       2020-09-20 20:23:24 +08:00
    cool,我觉得现在这样的文章似乎越来越少了,加油
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   995 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:43 · PVG 06:43 · LAX 14:43 · JFK 17:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.