数据库并发如何让数据操作串行化 您所在的位置:网站首页 并发怎么实现数据分析 数据库并发如何让数据操作串行化

数据库并发如何让数据操作串行化

2024-02-08 10:15| 来源: 网络整理| 查看: 265

本章主要讲解MySQL是如何在并发请求保证数据的正确性。 引入了一些概念,指引学习方向,文末有我们学习参考文章

概念 (针对于InnoDB)

学习一个新鲜事物的时,我们总会碰到一些新的概念或设计,如果你细心领悟或许可以举一反三,通过之前学过的东西与之关联。但是如果你并无感悟,倒也无妨。因为大多数你只需要整理后自己能记住就可以。毕竟我们不是开创者而是使用者。接下来我将要介绍几个概念或是设计是针对于今天所探讨的主题。

MVCC (多版本并发控制)

对于未接触过这个概念的人肯定是一脸雾水,那我只简介一下它的作用。如果想学习可以自行查找资料。

它会在每个数据行后面追加隐藏两个字段,分别代表创建(创建的事务版本号),删除(删除的事务版本号)。

事务版本号:每启动一个事务都会产生版本号

id name create_version delete_version 1 dog 1 2 1 pig 2 null 2 cat 2 3 3 cats 3 null

上表为MVCC的一个简图,我来描述一下它的经历。

事务1 :插入一条id=1,name=dog的数据。 事务2:更新了id=1,name=pig。 并且插入一条数据id=2,name=cat 事务3:插入了一条id=3,name=cats,并且删除了id=2的数据

有了这个设计我们就能弄出不同版本的查询结果(隔离级别中的快照读就与之相识)

获取最新版本(版本3)的数据,查询条件为:create_version>=3 and delete_version=null。 获取指定版本(版本2)的数据,查询条件为:create_version2)。 锁 (防止数据并发操作)

锁一个特别简单的名词,但是初学者未必能理的清楚概念。像我这样文字理解能不好的人就卡了半天。

最后我的理解是:阻碍你获取数据的就是锁。锁是你与数据交流间的一道屏障。

行锁 共享锁(S锁)又称为读锁(Share lock,简记为S锁),若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。 排它锁(X锁)又称为写锁((eXclusive lock,简记为X锁)),若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。

这里我进行了一个比喻,假设数据是一个透明的箱子。如果箱子里东西能看到就是可查询,能触碰到就是可修改。

共享锁:添加条件(能看到箱子里东西的事务都能添加,否者需要等待),相当于给箱子加了一个锁,这个锁只有自己能打开。

排它锁:添加条件(能触碰到箱子里东西的事务都能添加,否者需要等待),相当于打开箱子给里面东西套上一个盒子,再对盒子加锁,这个锁只有自己能打开

事务1 为数据添加共享锁,事务2能再添加共享锁吗?如果能,事务2能修改数据吗,事务1能修改数据吗? 事务1 为数据添加共享锁,事务2能添加排它锁吗?如果能,事务2能修改数据吗,事务1能修改数据吗? 事务1 为数据添加排它锁,事务2能添加共享锁吗?如果能,事务2能修改数据吗,事务1能修改数据吗? 事务1 为数据添加排它锁,事务2能添加排它锁吗?如果能,事务2能修改数据吗,事务1能修改数据吗? 间隙锁 (gap锁) 会在查询数据的两侧插入间隙锁,导致无法插入。 这与InnoDB索引顺序排序有关。 四种事务隔离

在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。我们的数据库锁,也是为了构建这些隔离级别存在的。

锁和多版本数据(MVCC)是 InnoDB 实现一致性读和隔离级别的手段。

因此,在不同的隔离级别下,InnoDB 处理 SQL 时采用的一致性读策略和需要的锁是不同的。

Read Uncommitted (RU)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed (RC)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read (RR)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

隔离级别与MVCC的关系

事务中sql语句有加锁与不加锁两种,我们把不加锁的定义为快照读,加锁的定义为当前读,以下是分类

快照读:就是select select * from table ….; 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。 select * from table where ? lock in share mode; S锁,Gap锁 select * from table where ? for update; X锁,Gap锁 insert; X锁,Gap锁 update ; X锁,Gap锁 delete; X锁,Gap锁

MVCC定义了隔离级别不同的快照读版本,只对RC与RR进行分析。

RC隔离级别:每次快照读都是获取最新版本。 RR隔离级别:每次快照读都是获取指定版本。 隔离级别与锁的关系

不同的隔离级别当前读加锁情况不同,只对RC与RR进行分析。

共同点:在添加X锁与S锁方面是一样的。 不同点:RR隔离级别有时还会添加Gap锁。 加锁分析 数据库加锁解锁时间点

数据库遵循的是两段锁协议,将事务分成两个阶段,加锁阶段和解锁阶段(所以叫两段锁)

事务 加锁/解锁处理 begin insert into test ….. 加insert对应的锁 update test set… 加update对应的锁 delete from test …. 加delete对应的锁 delete from test …. 事务提交时,同时释放insert、update、delete对应的锁

但在实际使用过程当中,MySQL做了一些改进,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录释放锁 (违背了二段锁协议的约束)。这样做,保证了最后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的。可见即使是MySQL,为了效率也是会违反规范的。(参见《高性能MySQL》中文第三版p181)

数据库如何加锁

数据库加锁是比较复杂,有比较多的情况。需要你了解InnoDB的索引机制。这里简单通过sql执行计划(explain)分析,步骤如下:

type=range key=PRIMARY:主键的范围扫描,会在主键B+树添加行锁。RR隔离级别下主键B+树会添加间隙锁。 key=唯一索引:唯一索引的范围扫描,会在主键B+树添加行锁,唯一索引B+树上添加行锁。RR隔离级别下唯一索引B+树会添加间隙锁。 key=普通索引:普通索引的范围扫描,会在主键B+树添加行锁,普通索引B+树上添加行锁。RR隔离级别下普通索引B+树会添加间隙锁。 type=ref key=普通索引:普通索引扫描,返回匹配某个单独值的所有行,会在主键B+树添加行锁,普通索引B+树上添加行锁。RR隔离级别下普通索引B+树会添加间隙锁。 type=eq_ref key=唯一索引:唯一索引扫描,返回匹配某个单独值行,会在主键B+树添加行锁,唯一索引B+树上添加行锁。 type=const key=主键索引:主键索引扫描,返回匹配某个单独值行,会在主键B+树添加行锁。 事务隔离中关于不可重复读,可重复读,幻读的理解

以下是作者的理解,符合所学知识,大家可以参考。

是否可重复读是针对于快照读,幻读是针对于当前读。 RC的不可重复读,是因为在RC隔离中快照读是获取最新快照版本,所有每次相同sql快照读的数据都可能不一样。 RR可重复读,是因为在RR隔离中快照读是获取指定快照版本,所有每次相同sql快照读数据的是一样的。

RC隔离中存在幻读可能性。举个例子有一个获取某表全部信息sql当前读(select from table for update)(sql的语义是锁住全表并获取最新信息),但是这时如果另一个事务执行(insert into table) 语句仍然可以插入,因为RC隔离中没有间隙锁。这会导致前面select from table for update 的数据不是最新有效数据。这就是幻读。

幻读——一个当前读的查询sql但是保证不了数据的正确性,这个查询就可能存在幻读。

RR隔离中有间隙锁,所以不会幻读。资料上会出现幻读的其实已经被InnoDB引擎优化了。 MySQL 架构图 (题外)

数据库并发如何让数据操作串行化

参考文档

真正理解Mysql的四种隔离级别MySQL锁总结MYSQL MVCC实现原理理解事务 - MySQL 事务处理机制Innodb中的事务隔离级别和锁的关系MySQL 加锁处理分析

mysql 事务隔离 锁 MVCC 本作品采用《CC 协议》,转载必须注明作者和本文链接


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有