(十三)深入理解 一致性锁定读 与 一致性非锁定读

一致性锁定读 与 一致性非锁定读

  • 产生的原因
    在mysql数据库中,有一个行锁的概念。行锁有两种类型:共享锁(s),排它锁(x);x锁和s锁是不能互相兼容的,而s锁与s锁是可以互相兼容的;在mysql的设计中,在写操作的时候会自动给选定行加上x锁,也就是所谓独占锁,即在没有释放x锁之前,任何会话都不能访问锁定行,我相信这个是没有问题的;但是这样会有问题,别的会话去读加了x锁的行时在正常逻辑下,为了保证数据一致性,我们在读的时候应该需要等待x锁释放再去读,从而可以得到最新最准确的数据,但是这样会严重降低数据库的性能,在数据库有写操作的情况下,读操作都需要等待;那到底在有写操作的时候,读操作要不要去等待呢?欣慰的是:mysql把这个选择权交给了我们,当有写(x锁)操作的情况下,希望读操作等待(加s锁)使用 一致性锁定读,希望读操作不等待(不加s锁)使用非锁定读。

  • 使用场景
    一致性锁定读:对数据一致性,实时性比较高的情况下(会破坏事务隔离性,比较慢,性能低)
    一致性非锁定读: 对数据一致性,实时性不高的情况下(数据可能不是最新的,不会破坏事务隔离性)

  • 一致性非锁定读(可重复读隔离级别)
    其实致性非锁定读的原理很简单,就是采用MVCC;也就是一个数据是有版本的,也就是历史数据,对于显示哪个历史版本的数据,这个和隔离级别有关,这里使用可重复读隔离级别作为例子,对于其他隔离级别的关于这个问题讨论,后面会进行总结。言归正传,你们想想,没有人会对历史数据进行修改吧,这样也就没有锁的概念一说了,mysql在默认情况下就是采用一致性非锁定读,即在读操作的时候,直接读取历史数据(不加锁),也就不会发生阻塞了,可重复读默认的历史版本数据是事务开始的时候的那个版本的数据。
    在这里插入图片描述
    设置隔离级别为 可重复读,并且打开两个客户端
    在这里插入图片描述
    在这里插入图片描述
    打开了两个客户端A B 客户端,并且读到了一样的数据
    在这里插入图片描述
    在这里插入图片描述
    我们在A客户端的事务中执行了一条update语句,这个时候id=1的记录被自动加上了x锁
    我们在B 客户端执行了两条select ,第一条是采用mysql默认非锁定读,也就是没有加锁,正常查询到老版本数据;但是第二条我手动加了s锁,就是采用了锁定读,这个时候就等待A客户端X锁的释放(采用锁定读有两种方式,一种是这种加s锁的,一种是 for update加x锁的)
    在这里插入图片描述
    在这里插入图片描述
    在A客户端中,我commit了事务,对x锁进行了释放
    在B客户端中,由于A已经释放了x锁,B客户端阻塞解除马上查询到了最新数据,发现在可重复读的隔离级别下,在使用一致性锁定读的情况下,两次读到了不一样的结果,也就是破坏了隔离性,同时也说明了一致性读的特点,总是读取最新的数据。

  • 可重复读隔离级别总结
    在可重复读隔离级别中(一个事务中),在使用 一致性非锁定读时(默认不加锁),读取的总是事务开始的那个版本数据,数据可能不是最新的;在使用 一致性锁定读时(加x锁或者s锁),读取的总是当前最新的数据;也就是说在可重复读隔离级别中一致性锁定读 与 一致性非锁定读读取到的数据不一定一样(在开启事务后,有其他事务修改了数据时不一致,否则一致)

  • 已提交隔离级别总结
    在已提交隔离级别中(一个事务中),一致性锁定读 与 一致性非锁定读读取到的数据总是一样的。因为即使在开启事务后,有其他的事务对数据进行了修改,一致性非锁定读总是读取最新的那个快照,而一致性锁定读本身就是读取最新的那个快照。

发布了65 篇原创文章 · 获赞 11 · 访问量 7171

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/93687340