一文带你了解数据库隔离级别和锁之间的联系

前言

隔离级别和数据库锁之间有什么关联呢

本文就和大家聊聊这两者之间的联系,希望对大家有帮助!

聊聊两者之间的联系

在具体聊之前,咱先记住一句话: 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。

首先来了解下有哪四种隔离级别

  • 读未提交:(Read Uncommitted)
  • 读已提交(Read Committed) 大多数数据库默认的隔离级别
  • 重复读(Repeatable-Read) mysql数据库所默认的级别
  • 序列化(serializable)

四种隔离级别具体实现和不同

首先程序是可以并发执行的,同样,在MySQL中,一个表可以由两个或多个进程同时来读写数据,这是没有问题的。

比如,此时有两个进程来读数据,这也没什么问题,允许。但是如果一个进程在读某一行的数据的过程中,另一个在进程又往这一行里面写数据(改、删),那结果会是如何?

同样,如果两个进程都同时对某一行数据进行更改,以谁的更改为准?那结果又会怎样,不敢想象,是不是数据就被破坏掉了。所以此时是冲突的。

既然会冲突就要想办法解决,靠谁来解决,这时候就是靠 锁机制 来维护了。怎么使用锁来使它们不冲突呢?

在事务开始的时候可以给要准备写操作的这一行数据加一个排它锁,如果是读操作,就给该行数据一个读锁。这样之后,在修改该行数据的时候,不让其他进程对该行数据有任何操作。

而读该行数据的时候,其他进程不能更改,但可以读。 读或写完成时,释放锁,最后commit提交。 这时候读写就分离开了,写和写也就分离开了。

mysql开发者给这个解决冲突的方案起了一个名字叫做: 读未提交 :(Read Uncommitted)。这也就是事务的第一个隔离性。

注意:上面的加锁和释放锁的过程由mysql数据库自身来维护,不需要我们人为干涉

但是这个程度的隔离性仅仅是不够的。看下面的测试结果

1、A修改事务级别为:未提交读。并开始事务,对user表做一次查询:

一文带你了解数据库隔离级别和锁之间的联系

2、B事务更新一条记录:

一文带你了解数据库隔离级别和锁之间的联系

3、此时B事务还未提交,A在事务内做一次查询,发现查询结果已经改变:

一文带你了解数据库隔离级别和锁之间的联系

4、B进行事务回滚:

一文带你了解数据库隔离级别和锁之间的联系

5、A再做一次查询,查询结果又变回去了:

一文带你了解数据库隔离级别和锁之间的联系

由试验得知:在一个进程的事务当中,我更改了其中的一行数据,但是我修改完之后就释放了锁,这时候另一个进程读取了该数据,此时先前的事务是还未提交的,直到我回滚了数据,另一个进程读的数据就变成了无用的或者是错误的数据。

我们通常把这种数据叫做脏数据,这种情况读出来的数据叫做 賍读

怎么办呢?当然还是靠锁机制。

无非是锁的位置不同而已,之前是只要操作完该数据就立马释放掉锁,现在是把释放锁的位置调整到事务提交之后,此时在事务提交前,其他进程是无法对该行数据进行读取的,包括任何操作。

那么数据库为此种状态的数据库操作规则又给了一个名字叫做: 读已提交 (Read Committed),或者也可以叫不可重复读。这也就是事务的第二个隔离性。

在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……

继续看下面的测试结果

1、把隔离性调为READ-COMMITTED(读取提交内容)设置A的事务隔离级别,并进入事务做一次查询:

一文带你了解数据库隔离级别和锁之间的联系

2、B开始事务,并对记录进行修改:

一文带你了解数据库隔离级别和锁之间的联系

3、A再对user表进行查询,发现记录没有受到影响:

一文带你了解数据库隔离级别和锁之间的联系

4、B提交事务:

一文带你了解数据库隔离级别和锁之间的联系

5、A再对user表查询,发现记录被修改:

一文带你了解数据库隔离级别和锁之间的联系

试验进行到这里,你会发现,在同一个事务中如果两次读取相同的数据时,最后的结果却不一致。

这里我们把这种现象称为: 不可重复读 。因为在第一个事务读取了数据之后,此时另一个事务把该数据给修改了,这时候事务提交,那么另一个事务在第二次读取的时候,结果就不一样,一个修改前的,一个是修改后的。

但是细心的你会发现,既然你说此种隔离性是在事务提交后才释放锁,那么在试验过程中,在该数据未提交前,另一个事务为什么也是仍然可以读取的呀。

是上面测试错了吗?不是的;

在这里mysql使用了一个并发版本控制机制,他们把它叫做MVCC,通俗的也就是说:mysql为了提高系统的并发量,在事务未提交前,虽然事务内操作的数据是锁定状态,但是另一个事务仍然可以读取数据的 快照版本 ;像 Oracle等大多数数据库默认的就是 读提交 这个级别的隔离性的。

但是mysql 的默认隔离级别却不是这个

而且不只是像上面在更新数据时出现这个问题,在插入数据时仍然会造成类似的这样一种现象: mysql虽然锁住了正在操作的数据行,但它仍然不会阻止另一个事务往表插入新行新的数据。

比如:一个事务读取或更新了表里的所有行,接者又有另一个事务往该表里插入一个新行,在事务提交后;

原来读取或更改过数据的事务又第二次读取了相同的数据,这时候这个事务中两次读取的结果集行数就不一样。原来更新了所有行,而现在读出来发现竟然还有一行没有更新。这就是所谓的 幻读

为了防止在同一事务中两次读取数据不一致,(包括不可重读和幻读),接下来该如何继续做呢

mysql依然采取的是MVCC并发版本控制来解决这个问题,还是读取的快照数据。

具体是:如果事务中存在多次读取同样的数据,MySQL第一次读的时候仍然会保持选择读最新提交事务的数据,当第一次之后,之后再读时,mysql会取第一次读取的数据作为结果。

这样就保证了同一个事务多次读取数据时数据的一致性。这时候,mysql把这种解决方案叫做: 可重复读 (Repeatable-Read),也就是上述所写的第三个隔离性,也是mysql默认的隔离级别。

注意:在可重复读的隔离级别下,除了会保证读操作的一致性外,在更新操作(当前读)时也会保证数据的一致性,避免出现不可重复读和幻读的错误;

具体是:在MySql的可重复读的隔离级别下,一个事务中更新数据,并且事务不提交,另启一个事务insert插入新数据,这时候是无法插入新数据的,插入操作被阻塞;为什么被阻塞呢?

因为在第一个事务中进行更新数据时(当前读),会使用 行锁 + 间隙锁 将表锁住了,所以在第二个事务中插入操作被阻塞;只有当第一个事务提交后,第二个事务中的插入操作才能被执行;

如果不阻塞的话,会存在什么问题? 会存在 幻读 的问题;例如:本来将全表数据的某个字段全部进行了更新,但是由于后面新增了数据,这些新增数据的那个字段并没有被更新,再次查看时就跟出现了幻觉一样;所以为了解决幻读的问题, 在可重复读隔离级别中提供了间隙锁,使用行锁+间隙锁将表锁住,让所有操作都不能修改数据 。

注意:innodb存储引擎中有对锁等待超时时间的配置,在规定时间内没有获取到锁的话,则此事务被中断,需要应用代码进行手动回滚或重试;

注意:幻读和不可重复读的区别:

  • 幻读是针对的一批数据记录整体
  • 不可重复读针对的是同一数据项的记录

最后这个时候,该我们的最后一种隔离级别也是最高的隔离级:别序列化(serializable)登场了

该隔离级别会自动在锁住你要操作的整个表的数据,如果另一个进程事务想要操作表里的任何数据就需要等待获得锁的进程操作完成释放锁。

可避免脏读、不可重复读、幻读的发生。当然性能会下降很多,会导致很多的进程相互排队竞争锁。

后记

上面所说的四种隔离性的锁机制应用是数据库自动完成的,不需要人为干预。

隔离级别的设置只对当前会话连接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效 。

来源:https://www.tuicool.com/articles/rm6v2uB

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容