【mysql】细说 数据库隔离级别 及实现

【mysql】细说 数据库隔离级别 及实现网上大多数关于隔离级别的文章都是讲了事务中的问题以及隔离级别可以解决的问题,我这次想看看数据库底层是如何实现隔离级别的。不过还是先来回顾一下隔离级别以及可能发生的问题。1.脏读:指的是一个事务的读操作读到了另一个未提交的事务修改的值。比如下面的场景:脏读的问题是,读到的值可能会被回滚,那么这个值就是失效的,不能继续使用,否则会有一致性问题。2.不可重复读:指的是一个事务读…

大家好,又见面了,我是你们的朋友全栈君。

网上大多数关于隔离级别的文章都是讲了事务中的问题以及隔离级别可以解决的问题,我这次想看看数据库底层是如何实现隔离级别的。

不过还是先来回顾一下隔离级别以及可能发生的问题。

1.脏读:指的是一个事务的读操作读到了另一个未提交的事务修改的值。比如下面的场景:

【mysql】细说 数据库隔离级别 及实现

脏读的问题是,读到的值可能会被回滚,那么这个值就是失效的,不能继续使用,否则会有一致性问题。

 

2.不可重复读:指的是一个事务读了同一个值两次,但是两次的值不同,因为中间另一个事务修改了这个值,比如下面的场景:

【mysql】细说 数据库隔离级别 及实现

t2事务是已提交的,所以t1的第二次读取是可以读到的。

 

3.幻读:仍然指的是一个事务中读了两次,结果不同,但是与不可重复读不同的是,这里不同是因为别的事物做了插入操作,而且读的条件是一个范围的条件,这样第二次会多读到一条数据,比如下面的例子:

【mysql】细说 数据库隔离级别 及实现

 

相应的有四种隔离级别,不同程度的解决了上面的问题:

【mysql】细说 数据库隔离级别 及实现

可以看到隔离界别越高,解决的问题就越多,但是并行化程度也越低,效率也越低。

 

那么数据库是如何实现隔离界别呢?下面以mysql innodb引擎来说下。事务隔离性,本质上解决事务的读写冲突的,在mysql中,读操作被实现为一种叫做“非锁定读取“的技术。什么意思,我们通常会说数据库里有共享锁和排它锁,读操作就是共享锁,只有共享锁和共享锁是非互斥的,那么如果一个读操作要在一个正在被修改的数据上进行,那么是无法加上获取该行对象的共享锁的,这便是数据库串行化隔离界别的实现方式,但是在其余的隔离界别下,我们不需要这么严格的隔离,我们允许了读操作可以在正在被修改的数据上即加上了排它锁的行数据上进行,这就是所谓的”非锁定读取“概念。

那么,读取的结果是什么?这个还需要明白另一点,就是我们数据库MVCC和undo日志,我们每一次的修改操作,并不是直接对行数据进行操作,比如我们设置id为3的行的A属性为10,并不是直接修改表中的数据,而是新加一行,同时数据表其实还有一些隐藏的属性,比如每一行的事务id,所以每一行数据可能会有多个版本,每一个修改过它的事务都会有一行,并且还会有关联的undo日志,表示这个操作原来的数据是什么,可以用它做回滚。那么为什么要这么做?因为如果我们直接把数据修改了,那么其他事务就用不了原先的值了,违反了事务的一致性。那么一个事务读取某一行的数据到底返回什么结果呢?取决于隔离级别,如果是Read Committed,那么返回的是最新的事务的提交值,所以未提交的事务修改的值是不会读到的,这就是Read Committed实现的原理。如果是Read Repeatable级别,那么只能返回发起时间比当前事务早的事务的提交值和比当前事务晚的删除事务删除的值。这其实就是MVCC方式。所以在第二个例子中,t2事务发生在t1后面,所以它更新的值是不会被t1读取到的,所以t1两次读取的值相同,也就是可以重复读。

关于可串行化的隔离界别,也很简单,严格的按照加锁协议来就可以,该级别可以避免上述所有的问题。

在oracle等数据库中,为了避免幻读,只能采用可串行化隔离级别,但是在innodb引擎中,在Repeatable Read级别也可以实现,主要是一种叫做”Next Locking“的技术,一种特殊的锁。

正常的锁一般是锁一行,称为是Record锁,而”Next Lock“则是锁一个范围内的行,比如说第三个例子中,t1事务第一次查询的是10到30之间的数据,那么最终这些数据都要被上锁,那么后面t2事务想要插入数据就不行了,会被拒绝,再往后,t1的第二次读取就会和第一次一样了。innodb采用这样的办法,就在repeatable read级别解决了幻读的问题。

最后总结一下innodb里面的锁的互斥,在可串行化级别,严格按照加锁协议,只有共享锁可以并行,其他全部阻塞。但是在其他的隔离级别,就放宽了很多。不过写-写是肯定不行的,读-读是肯定行的,读-写也是可以的,只不过读到什么内容就由MVCC来决定,由具体的隔离级别决定,写-读一般都可以,只有在启用了”Next Locking“的情况下会被拒绝。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/141390.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux shell awk数组使用

    Linux shell awk数组使用awk中使用数组一.数组格式数组是一个包含一系列元素的表.格式如下:abc[1]=”xiaohong”abc[2]=”xiaolan”解释:abc:为数组名称[1]、[2]:为数组元素下标,可以理解为数组的第1个元素、数组的第2个元素”xiaohong”、”xiaolan”:元素内容数组arrray[index-express…

    2022年7月19日
    16
  • java多线程并发之旅-14-lock free queue 无锁队列[通俗易懂]

    java多线程并发之旅-14-lock free queue 无锁队列[通俗易懂]无锁队列能实现吗?上面说的加锁的环形队列,可以保证线程安全。但是加锁能不能去掉呢?答案是肯定的,请看下面的娓娓道来。i++是原子操作吗?i++和++i是原子操作吗?有一个很多人也许都不是很清楚的问题:i++或++i是一个原子操作吗?在上一节,其实已经提到了,在SMP(对称多处理器)上,即使是单条递减汇编指令,其原子性也是不能保证的。那么在单处理机系统中呢?在编译器对C/C++源代码…

    2022年7月19日
    20
  • 秋招手撕代码:用移位寄存器实现的序列检测器(verilog)「建议收藏」

    秋招手撕代码:用移位寄存器实现的序列检测器(verilog)「建议收藏」之前一直想当然的认为序列检测器就应该用状态机来实现,后面在qq群里看到有人面试的时候被问,除了用状态机实现序列检测外,还能使用什么方法实现序列检测?后面查找了资料,发现可以使用序列检测器,自己就动手写了一个。1、代码思路:将输入的数据存储在移位寄存器中,如果寄存器中的序列是我们要检测的序列就输出1.2、代码`timescale1ns/1ps/////////////////////////////////////////////////////////////////////////////

    2022年7月16日
    14
  • 实战技巧:网站死链检测及处理方法!

    实战技巧:网站死链检测及处理方法!无论什么样的网站都避免不了死链,那么网站死链如果检测并处理呢,很多的大型的网站死链可以说是成千上万,网站数据量有那么大,网站权重那么高,死链对网站的影响可以说是忽略不计,那么网站出现了死链要怎么才知道呢?怎么来检测网站的死链呢?检测完了后又应该怎么处理呢?以下就是东莞SEO分析的企业网站或是其他网站对死链的检测和正确的处理方法:分析网站死链检测的方法1、通常使用网站死链检测工具,…

    2022年7月23日
    27
  • RabbitMQ基础介绍与在java中使用-入门「建议收藏」

    RabbitMQ基础介绍与在java中使用-入门「建议收藏」前言:MQ做应用解耦,流量削峰这些是常识,RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库常用的主流的MQ有四个ActiveMQ:Apache下的一个子项目。使用Java完全支持JMS1.1和J2EE1.4规范的JMSProvider实现,少量代码就可以高效地实现高级应用场景。可插拔的传输协议支持,比如:

    2022年10月3日
    7
  • rpm卸载多个有依赖的rpm包[通俗易懂]

    rpm卸载多个有依赖的rpm包[通俗易懂][root@devOOo_3.1.0_src]#rpm-qlibxml2[root@devOOo_3.1.0_src]#rpm-qalibxml2*[root@dev~]#rpm-qa|greplibxml2libxml2-python-2.6.26-2.1.12libxml2-devel-2.6.26-2.1.12libxml2-2.6.26libxm…

    2022年9月22日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号