MySQL45学习幻读

1.什么是幻读

幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行

在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。

幻读仅专指“新插入的行”

幻读的例子:

  • 假设有一个幻读的情况:
  • 表 T(id,a) 里面只有一行数据 row(id=1,a=1,b=1)
时间顺序事务1事务2
time1select * from T where a = 1 for update (id=1,a=1)
time2什么都不做insert(id=2,a=1);
time3select * from T where a = 1 for update (id=1,a=1) (id=2,a=1)
  • time1的查询结果是(id=1,a=1)
  • time3的查询结果是(id=1,a=1),(id=2,a=1)
  • 同一个事务之中两次查询的结果不一致

2. 为什么要防止幻读

If we regard a set of rows as a data item, the new phantom child would violate the isolation principle of transactions that a transaction should be able to run so that the data it has read does not change during the transaction.

因为幻读违背了事务隔离原则
例子中的情况,按道理来说应该在a=1的数据上加锁,但是这里
事务在执行期间,事务读取到的数据本应该是不会变化的

3. 怎么幻读是怎么解决的

MySQL使用临键锁来解决幻读的问题,MySQL锁介绍

  • 临键锁 = 记录锁 + 间隙锁
  • 假设有个事务T1,进行了查询(当强读就是select ... for update)操作
  • MySQL会根据where条件,扫描索引(如果没有普通索引则扫描聚簇索引)
  • 扫描过的索引范围上加上记录锁间隙锁
  • 其他事务想要插入,得在插入操作之前加锁
  • 但是因为where条件扫描过的范围上已经被加上了间隙锁记录锁,所以insert操作会被阻塞
  • 必须等到事务T1释放锁,才能执行成功

例子

  • 设有表t,表中只有三列(id,a,b),id是主键,a上有索引
  • 表里有2条数据(id=1,a=1,b=1)(id=10,a=10,b=10)

例1:

T1:
start transaction;
select * from t where a > 5 for update;
  • 当前读语句会在a的索引上加三个锁
    1. 间隙锁:(1,10)开区间
    1. 记录锁:a=10
    1. 间隙锁:(10,supremum)开区间

例2:

T1:
start transaction;
select * from t where a = 10 for update;
  • 当前读语句会在a的索引上加三个锁
    1. 间隙锁:(1,10)开区间
    1. 记录锁:a=10
    1. 间隙锁:(10,supremum)开区间

例3:

T1:
start transaction;
select * from t where b = 10 for update;
  • 当前读语句会在id聚簇索引上加5个锁
    1. 间隙锁:(infimum,1)开区间
    1. 记录锁:id=1
    1. 间隙锁:(1,10)开区间
    1. 记录锁:id=10
    1. 间隙锁:(10,supremum)开区间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值