V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
cc959798
V2EX  ›  MySQL

mysql mvcc 机制控制幻读问题

  •  
  •   cc959798 · 2018-10-24 10:14:34 +08:00 · 3602 次点击
    这是一个创建于 2258 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说 事务 A select * from tb1

    里面有三条数据

    然后开启一个事务 B

    select * from tb1 里面也是三条

    然后事务 A 插入一条并提交

    事务 B 里面看到的还是三条

    但是根据 mysql 版本控制,每行记录都有一个时间戳是事务的 id,新的事务 id 比老的事务 id 要大,事务 select 找到的行是创建时间比当前事务 id 要小的或者等于的行,但是上面的例子是事务 B 的 id 肯定比事务 A 要大,但是提交了依然看不到这是为什么?

    14 条回复    2018-10-25 10:28:58 +08:00
    kuko126
        1
    kuko126  
       2018-10-24 12:01:22 +08:00   ❤️ 1
    看你事务隔离级别,RR 下 B 看不到 A 的插入是正常的
    lsongiu
        2
    lsongiu  
       2018-10-24 13:29:51 +08:00
    mysql 默认隔离级别是可重复读,这不就是可重复读吗
    cc959798
        3
    cc959798  
    OP
       2018-10-24 13:49:46 +08:00
    @kuko126 肯定是默认的
    cc959798
        4
    cc959798  
    OP
       2018-10-24 13:51:10 +08:00
    @lsongiu 问题是按照网上的原理说明,后开启的事务是可以查到自己开启后提交到事务的新插入的或者说变更的
    kuko126
        5
    kuko126  
       2018-10-24 13:59:07 +08:00
    @cc959798 mysql 的 RR 是解决了幻读问题的 所以看不到
    lsongiu
        6
    lsongiu  
       2018-10-24 14:15:31 +08:00
    @cc959798 那得等 A 事务提交之后才能查出来
    Codingless
        7
    Codingless  
       2018-10-24 14:17:45 +08:00
    可见性的判断不是通过比较行记录事务 ID 和当前事务 ID 的实现的,是通过比较行记录对应 MVCC 版本链上某个节点的事务 ID 和当前查询对应的 ReadView 中若干个值(具体的比较规则代码里很清楚)实现的,具体可以了解一下 MVCC 和 ReadView 实现相关的内容。
    zjsxwc
        8
    zjsxwc  
       2018-10-24 14:33:07 +08:00
    正常,Mysql 默认事务隔离级别 Repeatable Read 是会幻读的,想要不幻读需要开 Serializable 级别隔离
    cc959798
        9
    cc959798  
    OP
       2018-10-24 14:52:08 +08:00
    @lsongiu 事实是事务 A 提交了也查不出来,这个也是满足可重复读的特性
    lsongiu
        10
    lsongiu  
       2018-10-24 15:00:47 +08:00
    A ->开始 -> 修改 -> 提交
    b ->开始 ->第一次查询 ->第二次查询 。这时候查出出来的都是修改过的

    A ->开始 -> 修改 -> 提交
    b ->开始 ->第一次查询 ->第二次查询 。这时候查出出来的都是修改前的
    lsongiu
        11
    lsongiu  
       2018-10-24 15:01:11 +08:00
    。。。这万一还自动去空格啊。。白写了
    NNS71L068O2v70DB
        12
    NNS71L068O2v70DB  
       2018-10-24 15:01:49 +08:00
    我的理解,判断的不是事务 ID,而是系统版本号。每个行都有一个字段存系统版本号,版本号可能是时间戳,所以 a insert 操作的话,修改行版本号(时间戳)> b 的事务 id,所以对 b 不可见
    cc959798
        13
    cc959798  
    OP
       2018-10-25 10:26:24 +08:00
    @jojojo 但是怎么解释老的事务比如 A 能看到这个新的修改,A 的 id 是小于新产生的版本号的,感觉网上讲的都不清不楚,而且大部分都是复制粘贴
    cc959798
        14
    cc959798  
    OP
       2018-10-25 10:28:58 +08:00
    @lsongiu 对白写都是一样的。现在可以知道的是默认隔离级别下,两个事务开启,无论谁先谁后,只要新的事务再老的 commit 之前开启的话,两个事务里面无论怎么改,select 都是自己看到的,除非是加锁,就是直接读而不是快照读,关键不知道他是怎么实现的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2652 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:09 · PVG 23:09 · LAX 07:09 · JFK 10:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.