美文网首页
数据库隔离级别相关

数据库隔离级别相关

作者: FrankXu0808 | 来源:发表于2021-07-05 16:51 被阅读0次

1.数据库隔离级别
目前数据库MySQL 并发事务下,在不同的隔离级别下,可能会出现四个问题.分别是:脏写(Lost Update),脏读(Dirty Reads),不可重复读(Non-Repeatable Reads),幻读(Phantom Reads)。
数据库的隔离级别分别是: 未提交读(read uncommitted)、已提交读(read committed)、可重复读(repeatable read)、串行化(serializable)

2.各种数据库引擎的默认隔离级别

  • Mysql 可重复读
  • Oracle 读提交
  • Sql Server 读提交
    为什么Oracle和Sql Server的默认隔离级别是可提交?为什么Mysql是可重复读?
    首先隔离级别肯定不能是未提交读,读取未提交的数据太过危险。串行化的隔离级别基本意味着没有高并发,太严格。所以隔离级别就在已提交读和可重复读之间了。那么大多数的选择是已读提交,这是因为:
    (1)repeatable存在间隙锁会使死锁的概率增大,在RR隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行。
    (2)在RC级用别下,主从复制用什么binlog格式:row格式,是基于行的复制!

那为什么,在Oracle,SqlServer中都是选择读已提交(Read Commited)作为默认的隔离级别,为什么Mysql不选择读已提交(Read Commited)作为默认隔离级别,而选择可重复读(Repeatable Read)作为默认的隔离级别呢?

详细说明见:https://www.cnblogs.com/shoshana-kong/p/10516404.html

3.隔离级别举例
https://zhuanlan.zhihu.com/p/150107974

4.事务隔离级别是如何避免上述读写问题
(1)读未提交:一个事务可以读取到另一个事务未提交的修改。这会带来脏读、幻读、不可重复读问题。(基本没用)
(2)读已提交:一个事务只能读取另一个事务已经提交的修改。其避免了脏读,但仍然存在不可重复读和幻读问题。
(3)可重复读:同一个事务中多次读取相同的数据返回的结果是一样的。其避免了脏读和不可重复读问题,但幻读依然存在。
(4)串行化:事务串行执行。避免了以上所有问题。

以上是SQL-92标准中定义的四种隔离级别。在MySQL中,默认的隔离级别是REPEATABLE-READ(可重复读),并且解决了幻读问题。简单的来说,mysql的默认隔离级别解决了脏读、幻读、不可重复读问题。

不可重复读重点在于update和delete,而幻读的重点在于insert。

在这里,我们只讨论读已提交和可重复读。

我们可以通过MVCC,即多版本并发控制,来实现读已提交和可重复读的隔离机制。
MVCC如何实现数据库读已提交和可重复读这两种隔离级别?

MVCC其实主要包含三个概念:隐藏列,undo log,ReadView

隐藏列

在Innodb引擎中,每个数据表都会有两个隐藏列(其实准确来说是三个,还有一个叫隐藏id,因为innodb必须要有主键,如果建表时没有显式指定的话,就会生成这个隐藏id作为主键,当然这个隐藏id和mvcc没有关系,真正和mvcc有关系的其实是两个隐藏列),分别是trx_id,创建版本号;和roll_pointer,回滚指针。其中创建版本号其实就是创建该行数据的事务id。这些隐藏列对我们客户端来说是不可见的。

undo log

当事务对数据行进行一次更新操作时,会把旧数据行记录在一个叫做undo log的记录中,在undo log中除了记录数据行,还会记录下该行数据的对应的创建版本号,也就是生成这行数据的事务id嘛~然后将原来数据行中的回滚指针指向undo log记录的这行数据。然后再在原来数据表中进行一次更新操作,如果这次更新操作回滚了,那么就可以根据回滚指针去undo log中查找之前的数据进行复原。如果后续还有更新操作的话,就会在undo log中和之前的数据行形成一条链表,链表头就是最新的数据,这条链表就叫做版本链


版本链

(ps:数据本来是刘备,然后事务id为100的事务先修改成了关羽,再修改成了张飞,后面事务id为200的事务先修改成了赵云,再修改成了诸葛亮,)

事务的可见性都是基于这个undo log来实现的

ReadView

刚才说了更新操作,那查询操作呢?这才是实现不同隔离级别的关键地方

当进行查询操作时,事务会生成一个ReadView,ReadView是一个事务快照,准确来说是当前时间点系统内活跃的事务列表,也就是说系统内所有未提交的事务,都会记录在这个Readview内,事务就根据它来判断哪些数据是可见的,哪些是不可见的。

查询一条数据时,事务会拿到这个ReadView,去到undo log中进行判断。若查询到某一条数据:

  • 先去查看undo log中的最新数据行,如果数据行的版本号小于ReadView记录的事务id最小值,就说明这条数据对当前数据库是可见的,可以直接作为结果集返回
  • 若数据行版本号大于ReadView记录最大值,说明这条数据是由一个新的事务修改的,对当前事务不可见,那么就顺着版本链继续往下寻找第一条满足条件的
  • 若数据行版本号在ReadView最小值和最大值之间,那么就需要进行遍历了整个ReadView了,如果数据行版本号等于ReadView的某个值,说说明该行数据仍然处于活跃状态,那么对当前事务不可见

读已提交和可重复读的实现

ReadView就是这样来判断数据可见性的。

那又是如何实现读已提交和可重复读呢?其实很简单,就是生成ReadView的时机不同。

对读已提交来说,事务中的每次读操作都会生成一个新的ReadView,也就是说,如果这期间某个事务提交了,那么它就会从ReadView中移除。这样确保事务每次读操作都能读到相对比较新的数据

而对可重复读来说,事务只有在第一次进行读操作时才会生成一个ReadView,后续的读操作都会重复使用这个ReadView。也就是说,如果在此期间有其他事务提交了,那么对于可重复读来说也是不可见的,因为对它来说,事务活跃状态在第一次进行读操作时就已经确定下来,后面不会修改了。
(引用:https://www.pianshen.com/article/89531041786/

相关文章

  • MySQL 事务隔离级别

    一、MySQL 数据库命令 查看数据库版本: 查看数据库现在的隔离级别 修改隔离级别: 级别参数:1.READ-U...

  • MySQL_tx_isolation

    事务隔离级别 一、数据库事务隔离级别数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、...

  • MySQL数据库相关操作

    一、数据库隔离级别 查询数据库当前隔离级别 修改隔离级别 二、常用进程、锁命令 查看进程id 查询正在执行的进程 ...

  • Java面试——mysql数据库相关

    Java面试——mysql数据库相关 1,数据库隔离级别: 2,如果不考虑事务隔离性引发的安全性问题: 脏读:一个...

  • 聊聊MySQL的隔离级别

    原文:聊聊MySQL的隔离级别 | MySQL隔离级别原理参考:oracle - mysql - 数据库事务隔离级...

  • 数据库隔离级别相关

    1.数据库隔离级别目前数据库MySQL 并发事务下,在不同的隔离级别下,可能会出现四个问题.分别是:脏写(Lost...

  • MySQL事务隔离级别和实现原理,看这一篇就够了!!!

    经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么...

  • 数据库隔离级别实现(转发)

    数据库隔离级别及实现原理_滚蛋吧,生活。-CSDN博客_数据库隔离级别怎么实现的[https://blog.csd...

  • 2018-04-19Spring事务

    spring事务分为:5大隔离级别(数据库4大隔离级别) 7大传播属性 隔离级别理解就是对数据操作的隔离性操作,脏...

  • 数据库事务隔离级别 - 分析脏读 & 不可重复读 &am

    一 数据库事务的隔离级别 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read ...

网友评论

      本文标题:数据库隔离级别相关

      本文链接:https://www.haomeiwen.com/subject/cehiultx.html