专业汉语词典知识平台,分享汉字词语知识、历史文学知识解答!

励北网
励北网

数据库隔离级别,MySQL事务的四大隔离级别

来源:小易整编  作者:小易  发布时间:2023-02-28 05:02
摘要:数据库隔离级别,MySQL事务的四大隔离级别前言之前分析一个死锁问题,发现自己对数据库隔离级别理解还不够深入,所以趁着这几天假期,整理一下MySQL事务的四大隔离级别相关知识,希望对大家有帮助~事务什么是事务?事务,由一个有限的数据库操作序...

set session transaction isolation level read committed;begin;select* from account where id =1;

另开一个窗口打开mysql,也把事务隔离级别设置为read committed,开启事务B,执行以下操作

set session transaction isolation level read committed;begin;update account set balance=balance+20where id =1;

接着回事务A的窗口,再查account数据,发现数据没变:

数据库隔离级别,MySQL事务的四大隔离级别

我们再去到事务B的窗口执行commit操作:

commit;

最后回到事务A窗口查询,发现数据变了:

数据库隔离级别,MySQL事务的四大隔离级别

由此可以得出结论,隔离级别设置为已提交读(READ COMMITTED) 时,已经不会出现脏读问题了,当前事务只能读取到其他事务提交的数据。但是,你站在事务A的角度想想,存在其他问题吗?

读已提交的隔离级别会有什么问题呢?

在同一个事务A里,相同的查询sql,读取同一条记录(id=1),读到的结果是不一样的,即不可重复读。所以,隔离级别设置为read committed的时候,还会存在不可重复读的并发问题。

可重复读(Repeatable Read)

如果你的老板要求,在同个事务中,查询结果必须是一致的,即老板要求你解决不可重复的并发问题,怎么办呢?老板,臣妾办不到?来实践一下可重复读(Repeatable Read) 这个隔离级别吧~

数据库隔离级别,MySQL事务的四大隔离级别

哈哈,步骤1、2、6的查询结果都是一样的,即repeatable read解决了不可重复读问题,是不是心里美滋滋的呢,终于解决老板的难题了~

RR级别是否解决了幻读问题呢?

再来看看网上的一个热点问题,有关于RR级别下,是否解决了幻读问题?我们来实践一下:

数据库隔离级别,MySQL事务的四大隔离级别

由图可得,步骤2和步骤6查询结果集没有变化,看起来RR级别是已经解决幻读问题了~ 但是呢,RR级别还是存在这种现象:

数据库隔离级别,MySQL事务的四大隔离级别

其实,上图如果事务A中,没有 update accountsetbalance=200whereid=5;这步操作, select*fromaccountwhereid>2查询到的结果集确实是不变,这种情况没有幻读问题。但是,有了update这个骚操作,同一个事务,相同的sql,查出的结果集不同,这个是符合了幻读的定义~

这个问题,亲爱的朋友,你觉得它算幻读问题吗?

串行化(Serializable)

前面三种数据库隔离级别,都有一定的并发问题,现在放大招吧,实践SERIALIZABLE隔离级别。

把事务隔离级别设置为Serializable,开启事务A,查询account表数据

set session transaction isolation level serializable;select@@tx_isolation;begin;select* from account;

另开一个窗口打开mysql,也把事务隔离级别设置为Serializable,开启事务B,执行插入一条数据:

set session transaction isolation level serializable;select@@tx_isolation;begin;insert into account(id,name,balance) value(6,'Li',100);

执行结果如下:

数据库隔离级别,MySQL事务的四大隔离级别

由图可得,当数据库隔离级别设置为serializable的时候,事务B对表的写操作,在等事务A的读操作。其实,这是隔离级别中最严格的,读写都不允许并发。它保证了最好的安全性,性能却是个问题~

MySql隔离级别的实现原理

实现隔离机制的方法主要有两种:

  • 读写锁

  • 一致性快照读,即 MVCC

MySql使用不同的锁策略(Locking Strategy)/MVCC来实现四种不同的隔离级别。RR、RC的实现原理跟MVCC有关,RU和Serializable跟锁有关。

读未提交(Read Uncommitted)

官方说法:

SELECT statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used. Thus, using this isolation level, such reads are not consistent.

读未提交,采取的是读不加锁原理。

  • 事务读不加锁,不阻塞其他事务的读和写

  • 事务写阻塞其他事务写,但不阻塞其他事务读;

串行化(Serializable)

官方的说法:

InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. If autocommit is enabled, the SELECT is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plain SELECT to block if other transactions have modified the selected rows, disable autocommit.)

  • 所有SELECT语句会隐式转化为 SELECT...FOR SHARE,即加共享锁。

  • 读加共享锁,写加排他锁,读写互斥。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞。

MVCC的实现原理

MVCC,中文叫多版本并发控制,它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。它的实现依赖于隐式字段、undo日志、快照读&当前读、Read View,因此,我们先来了解这几个知识点。

隐式字段

对于InnoDB存储引擎,每一行记录都有两个隐藏列DBTRXID,DBROLLPTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列 DBROWID。

  • DBTRXID,记录每一行最近一次修改(修改/更新)它的事务ID,大小为6字节;

  • DBROLLPTR,这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;

  • DBROWID,单调递增的行ID,大小为6字节;

数据库隔离级别,MySQL事务的四大隔离级别

undo日志

  • 事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响。

  • undo日志是逻辑日志。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert记录,当update一条记录时,它记录一条对应相反的update记录。

  • 存储undo日志的地方,就是回滚段。

多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(DBROLLPTR)连一条Undo日志链。

我们通过例子来看一下~

mysql> select* from account ;+----+------+---------+| id | name | balance |+----+------+---------+|  1| Jay|     100|+----+------+---------+1 row inset(0.00 sec)

  • 假设表accout现在只有一条记录,插入该该记录的事务Id为100

  • 如果事务B(事务Id为200),对id=1的该行记录进行更新,把balance值修改为90

事务B修改后,形成的Undo Log链如下:

数据库隔离级别,MySQL事务的四大隔离级别

快照读&当前读

快照读:

读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读,如:

select* from account where id>2;

当前读:

读取的是记录数据的最新版本,显示加锁的都是当前读

select* from account where id>2lockin share mode;select* from  account where id>2for update;

Read View

  • Read View就是事务执行快照读时,产生的读视图。

  • 事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把它们放到一个列表里。

  • Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~

为了下面方便讨论Read View可见性规则,先定义几个变量

  • m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List。

  • minlimitid:m_ids事务列表中,最小的事务ID

  • maxlimitid:m_ids事务列表中,最大的事务ID

  • 如果DBTRXID < minlimitid,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。

  • 如果DBTRXID > m_ids列表中最大的事务id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。

  • 如果 minlimitid =<dbTRXID<= maxlimitid,需要判断mids.contains(DBTRX_ID),如果在,则代表Read View生成时刻,这个事务还在活跃,还没有Commit,你修改的数据,当前事务也是看不见的;如果不在,则说明,你这个事务在Read View生成之前就已经Commit了,修改的结果,当前事务是能看见的。</db

注意啦!! RR跟RC隔离级别,最大的区别就是:RC每次读取数据前都生成一个ReadView,而RR只在第一次读取数据时生成一个ReadView。

已提交读(READ COMMITTED) 存在不可重复读问题的分析历程

我觉得理解一个新的知识点,最好的方法就是居于目前存在的问题/现象,去分析它的来龙去脉~ RC的实现也跟MVCC有关,RC是存在重复读并发问题的,所以我们来分析一波RC吧,先看一下执行流程

数据库隔离级别,MySQL事务的四大隔离级别

假设现在系统里有A,B两个事务在执行,事务ID分别为100、200,并且假设存在的老数据,插入事务ID是50哈~

事务A 先执行查询1的操作

# 事务A,Transaction ID 100begin;查询1:select*  from account WHERE id = 1;

事务 B 执行更新操作,id =1记录的undo日志链如下

begin;update account set balance =balance+20where id =1;

数据库隔离级别,MySQL事务的四大隔离级别

回到事务A,执行查询2的操作

begin;查询1:select*  from account WHERE id = 1;查询2:select*  from account WHERE id = 1;

查询2执行分析:

  • 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)在活跃,所以ReadView的m_ids列表内容就是[200]

  • 由上图undo日志链可得,最新版本的balance为1000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务A)不可见。

  • 我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录200,所以这个版本可见,因此,查询2的结果,就是返回balance=100这个记录~~

我们回到事务B,执行提交操作,这时候undo日志链不变

begin;update account set balance =balance+20where id =1;commit

数据库隔离级别,MySQL事务的四大隔离级别

再次回到事务A,执行查询3的操作

begin;查询1:select*  from account WHERE id = 1;查询2:select*  from account WHERE id = 1;查询3:select*  from account WHERE id = 1;

查询3执行分析:

  • 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)已经提交,不再活跃,所以ReadView的m_ids列表内容就是空的了。

  • 所以事务A直接读取最新记录,读取到balance =120这个版本的数据。

所以,这就是RC存在不可重复读问题的过程啦~有不理解的地方可以多读几遍哈~

可重复读(Repeatable Read)解决不可重复读问题的一次分析

我们再来分析一波,RR隔离级别是如何解决不可重复读并发问题的吧~

你可能会觉得两个并发事务的例子太简单了,好的!我们现在来点刺激的,开启三个事务~

数据库隔离级别,MySQL事务的四大隔离级别

假设现在系统里有A,B,C两个事务在执行,事务ID分别为100、200,300,存量数据插入的事务ID是50~

# 事务A,Transaction ID 100begin;UPDATE account SET balance = 1000  WHERE id = 1;


本文地址:百科问答频道 https://www.neebe.cn/wenda/903503_2.html,易企推百科一个免费的知识分享平台,本站部分文章来网络分享,本着互联网分享的精神,如有涉及到您的权益,请联系我们删除,谢谢!


百科问答
小编:小易整编
相关文章相关阅读
  • 数据库管理是什么意思?

    数据库管理是什么意思?

    数据库管理是指通过数据库管理系统来管理、访问存储在数据库中的数据的过程。它也和实现电子档案库、图书馆的相关软件的开发有着密切的联系。数据库管理特别强调数据的独立性和可移植性,从而保证数据的可靠性和安全性。数据库管理的主要作用,是把一些内容...

  • 共享数据库是什么意思?

    共享数据库是什么意思?

    共享数据库是一种常见的开发工作流程,即团队中的所有开发人员都共享某一个数据库的访问权限,都使用该数据库来支持应用程序开发。无需为每个工程师配置基础架构,使安装成本降至最低,因而人们愿意选择它。但由于工程师做出改变的同时不得不承担着影响其他...

  • 公用数据库是什么

    公用数据库是什么

    公共数据库是指数据库软件(如Access、SQLServer等)生成的各种包含元器件信息的表格文件。AltiumDesign通过创建和使用关联数据库DBLib文件,可直接从公共数据库调取元器件并通过连接库文件与公共数据库保持同步更新。公共...

  • 关系型数据库的基本原理是什么

    关系型数据库的基本原理是什么

    关系型数据库采用的是关系模型,即把数据组织成一个或多个表格(称为关系),每个表格包含多个列,每行代表一个记录。这种模型的优点是简单易懂,容易维护,便于数据查询和修改。其次是数据结构,关系型数据库采用的是二维表格结构,每个表格有一个主键用于唯...

  • 云数据库RDS是什么

    云数据库RDS是什么

    关系型数据库(RDS)是一种稳定可靠、可弹性伸缩的在线数据库服务。具有多重安全防护措施和完善的性能监控体系,并提供专业的数据库备份、恢复及优化方案,使您能专注于应用开发和业务发展。关系型数据库(RelationalDatabaseSer...

  • 数据库系统由哪几部分组成,什么是数据库系统

    数据库系统由哪几部分组成,什么是数据库系统

    数据库系统由哪几部分组成,什么是数据库系统各位小伙伴们,最近忙于自己的事情,难得闲下心来想在这里记录些什么,在自己做网络知识相关笔记的时候,才想起自己的知识库里存有之前学习的数据库相关的知识,所幸的是自己的勤快做的笔记能够存留下来,于是自己...

  • 外键约束怎么写,MySql外键约束教程

    外键约束怎么写,MySql外键约束教程

    外键约束怎么写,MySql外键约束教程学习目标掌握外键约束的添加方法知道外键约束字段的添加及删除规则1.多表查询概述l实际开发中,一个项目通常需要很多张表才能完成。l例如:一个商城项目就需要分类表(category)、商品表(product...

  • 关系数据库有哪几种,常用关系数据库介绍

    关系数据库有哪几种,常用关系数据库介绍

    关系数据库有哪几种,常用关系数据库介绍数据库管理系统是用于创建,维护与管理数据库的系统软件,是搭建其他应用环境所必备的软件之一,是软件系统架构的重要组成部分。对于IT人员,不论是开发还是测试人员都是其必须掌握的软件。对于开发可以说是他们吃饭...

  • 周排行
  • 月排行
  • 年排行

精彩推荐