• MySQL--REPEATABLE-READ隔离级别下读取到的“重复数据”


    在MySQL中,使用MVCC来实现REPEATABLE-READ隔离级别,由于SELECT操作不会对数据加锁,其他回话可以修改当前回话所读取过的数据而不会被阻塞,因此读写不冲突。

    在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。(抄自MySQL 加锁处理分析

    当事务中进行查询时,MySQL会把快照读和当前读的结果进行合并再返回给客户端,而这个合并可能导致一些奇特的结果。

    生成测试数据:

    drop table tb002;
    create table tb002(id int primary key,c2 int,unique index uni_c2(c2));
    begin;
    insert into tb002(id,c2) select 1,1;
    insert into tb002(id,c2) select 2,2;
    insert into tb002(id,c2) select 4,4;
    commit;

    假设有回话A和回话B,均使用REPEATABLE-READ隔离级别

    ##========================================================##

    首先回话A执行SQL:

    begin;
    select * from tb002;

    返回结果如下:

    ##========================================================##

    然后回话B执行SQL:

    begin;
    delete from tb002 where id=2;
    commit;

    由于回话A没有加锁,所以回话B能顺利完成删除并提交事务,当前数据库中无C2=2的记录,且会话B提交事务释放锁。

    ##========================================================##

    回到回话A执行SQL:

    insert into tb002(id,c2) select 3,2;
    

    由于当前数据库中无C2=2的记录,且其他回话没有在此C2=2的范围上加锁,因此回话A可以完成C2=2的数据插入。

    在回话A上再次进行查询:

    select * from tb002;

    返回结果如:

    C2上有唯一索引,但为什么查询结果中仍包含两条C2=2的记录呢?ID=2的记录属于快照读的数据,ID=3的记录数据当前读的数据,MySQL将当前读和快照读的数据进行简单的合并后返回给客户端,并不检查“结果数据是否满足唯一索引”的要求。

    ##========================================================##

    上面的测试针对唯一索引进行,那如果针对主键会有啥区别呢?

    将插入SQL修改为:

    insert into tb002(id,c2) select 2,3;

    即回话B删除的ID值和回话A新插入的ID值相同情况下,最后的查询结果并不会包含两条相同ID的记录,对于“快照读”和“当前读”两个结果集存在"主键冲突“的情况,最终返回客户端的结果会”丢弃“快照读中的”老版本“记录,保留最新版本的记录。

    可见对于主键不存在上述问题。

    ##========================================================##

    总结:

    在基于MVCC实现的REPEATABLE-READ隔离级别下,由于快照读和当前读的影响,会导致返回数据结果集超过”期望结果集“的情况,甚至返回结果集中包含重复的”唯一索引键“,但返回结果集中不会包含重复的“主键”(PS:单表查询的前提下)。

    如果在事务中包含先插入后查询的情况,应该考虑上述问题对业务的影响。

    ##========================================================##

  • 相关阅读:
    windows环境下安装mysql5.7.20
    一次完成对多个子节点的全部父级节点查询
    更新数据库中值为拼接字符串的字段
    根据父节点编号查询子节点名称,孙节点个数
    Java文件流下载并提示文件不存在
    Nginx 反向代理Tomcat服务器获取真实IP问题
    Tomcat启动堆栈异常
    转一些思想 代码大全的
    一些方案
    UML建模工具
  • 原文地址:https://www.cnblogs.com/TeyGao/p/7846695.html
Copyright © 2020-2023  润新知