【MySQL】事务管理 -- 详解

一、前言

CURD 不加控制,会有什么问题?


CURD 满足什么属性,能解决上述问题?
  1. 买票的过程得是原子的。
  2. 买票应该不能受互相的影响。
  3. 买完票应该要永久有效。
  4. 买前和买后都要是确定的状态。

什么是事务?
  • 事务就是一组 DML 语句组成,这些语句在逻辑上存在相关性,这一组 DML 语句要么全部成功,要么全部失败,是一个整体。MySQL 提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。
  • 事务就是要做的或所做的事情,主要用于处理操作量大复杂度高的数据。假设一种场景:你毕业了,学校的教务系统后台 MySQL 中,不再需要你的数据,要删除你的所有有关信息(一般不会),那么要删除你的基本信息(姓名、电话、籍贯等)的同时,也删除和你有关的其他信息,比如:你的各科成绩,你的在校表现,甚至你在论坛发过的帖子、文章等。这样就需要多条 MySQL 语句构成,那么所有这些操作合起来就构成了一个事务
  • 正如上面所说,一个 MySQL 数据库,可不止你一个事务在运行,同一时刻甚至有大量的请求被包装成事务,再向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL,最多很多 SQL,这样如果大家都访问同样的表数据,在不加保护的情况下就绝对会出现问题。甚至因为事务由多条 SQL 构成,那么也会存在执行到一半出错或者不想再执行的情况,那么已经执行的怎么办呢?

一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性:

  • 原子性一个事务(transaction中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性在事务开始之前和事务结束以后,数据库的完整性没有被破坏这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • 隔离性数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted读提交(read committed可重复读(repeatable read串行化(Serializable
  • 持久性事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
上面四个属性,可以简称为 ACID
  • 原子性Atomicity,或称不可分割性)
  • 一致性Consistency)
  • 隔离性Isolation,又称独立性)
  • 持久性Durability)

为什么会出现事务?
事务被 MySQL 编写者设计出来, 本质是为了当应用程序访问数据库时, 事务能够简化我们的编程模型, 不需要我们去考虑各种各样的潜在错误和并发问题。 可以想一下当我们使用事务时, 要么提交, 要么回滚, 我们不会去考虑网络异常了, 服务器宕机了, 同时更改一个数据该怎么办。
因此事务本质上是 为了应用层服务 的。 而不是伴随着数据库系统天生就有的。
(提示:我们后面把 MySQL 中的一行信息,称为一行记录。)

二、事务的版本支持

MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务 MyISAM 不支持

1、查看数据库引擎

(1)表格显示


(2) 行显示


三、事务提交方式

1、事务的提交方式

常见的事务的提交方式有两种:

  1. 自动提交
  2. 手动提交

2、查看事务提交方式

  • set 来改变 MySQL 的自动提交模式:


四、事务常见操作方式

1、练习 —— 简单银行用户表

(1)提前准备
  • Centos 7 云服务器,默认开启 3306 mysqld 服务

  • 使用 Win cmd 远程访问 Centos 7 云服务器,mysqld 服务(需要 Win 上也安装了 MySQL,这里看到结果即可)
  • 注意:使用本地 MySQL 客户端可能看不到链接效果,本地可能使用域间套接字查不到链接。
C:\Users\whb>mysql -uroot -p -h42.192.83.143
Enter password: ***********
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3484
Server version: 5.7.33 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

  • 使用 netstat 查看链接情况,可知:MySQL 本质是一个客户端进程


  • 为了便于演示,我们将 MySQL 的默认隔离级别设置成读未提交。


(2)创建测试表

(3)正常演示 —— 证明事务的开始与回滚


(4)非正常演示
A. 证明未 commit,客户端崩溃,MySQL 自动会回滚(隔离级别设置为读未提交)
  • 终端 A


  • 终端 B


B. 证明 commit 了,客户端崩溃,MySQL 数据不会在受影响,已经持久化
  • 终端 A


  • 终端 B


C. 对比试验。证明 begin 操作会自动更改提交方式,不会受 MySQL 是否自动提交影响
  • 终端 A


  • 终端 B


D. 证明单条 SQL 与事务的关系
a. 实验一
  • 终端 A


  • 终端 B


b. 实验二
  • 终端 A


  • 终端 B


2、结论

  • 只要输入 begin / start transaction,事务便必须要通过 commit 提交,才会持久化,与是否设置 set autocommit 无关
  • 事务可以手动回滚,同时,当操作异常,MySQL 会自动回滚。
  • 对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交。(select 有特殊情况,因为 MySQL 有 MVCC )
  • 从上面的例子,我们能看到事务本身的原子性(回滚),持久性(commit)。

3、事务操作注意事项

  • 如果没有设置保存点,也可以回滚,但只能回滚到事务的开始。直接使用 rollback(前提是事务还没有提交)。
  • 如果一个事务被提交了(commit),则不可以回退(rollback)。
  • 可以选择回退到哪个保存点。
  • InnoDB 支持事务, MyISAM 不支持事务
  • 开始事务可以用 start transactionbegin

五、事务隔离级别

1、如何理解隔离性

  • MySQL 服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行。
  • 一个事务可能由多条 SQL 构成,也就意味着任何一个事务都有执行前、执行中、执行后的阶段。而所谓的原子性,其实就是让用户层要么看到执行前,要么看到执行后,执行中出现问题可以随时回滚。所以单个事务对用户表现出来的特性就是原子性
  • 但毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个 SQL 时,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。
  • 假设你妈妈给你说:你要么别学,要学就学到最好。至于你怎么学,中间有什么困难,你的妈妈并不关心。那么你的学习对于你妈妈来说,就是原子的。那么你的学习过程很容易受别人干扰,此时就需要将你的学习隔离开,以保证你的学习环境是健康的。
  • 在数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性
  • 在数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

2、隔离级别

  • 读未提交【Read Uncommitted在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的)但相当于没有任何隔离性,也会有很多并发问题,如脏读、幻读、不可重复读等,我们前面为了做实验方便,用的就是这个隔离性。
  • 读提交【Read Committed该隔离级别是大多数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select,可能得到不同的结果。
  • 可重复读【Repeatable Read这是 MySQL 默认的隔离级别,它确保同一个事务在执行中,多次读取操作数据时,会看到同样的数据行,但是会出现幻读问题。
  • 串行化【Serializable这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,但可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)。
隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见的有:表锁、行锁、读锁、写锁、间隙锁(GAP)、Next-Key 锁( GAP+ 行锁) 等。不过,我们目前现有这个认识就行,先关注上层使用。

3、查看与设置隔离性

(1)查看


(2)设置
  • 设置当前会话 / 全局隔离级别
set [session | global] transaction isolation level {read uncommitted | read committed | repeatable read | serializable} ;

注意:改变当前会话隔离级别,重启不受影响。但改变全局隔离级别的话,重启之后默认值会发生改变。


  • 设置当前会话隔离性,另起一个会话,看不多,只影响当前会话
串行化:
set session transaction isolation level serializable;

  • 设置全局隔离性,另起一个会话,会被影响

set global transaction isolation level read uncommitted;

注意:如果没有现象,关闭 M ySQL  客户端,重新连接。

4、读未提交【Read Uncommitted 

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用。
  • 终端 A


  • 终端 B

一个事务在执行中,读到另一个执行中事务的更新或其他操作,但是未 commit 的数据,这种现象叫做脏读(dirty read)。 


5、 读提交【Read Committed】

  • 终端 A


  • 终端 B

终端 B 进行第 2 次 select * from account 之前,此时还在当前事务中,并未  commit ,那么就造成了在同一个事务内进行同样的读取,不同的时间段 依旧还在事务操作中) 读取到了不同的值,这种现象叫做不可重复读 non reapeatable read)

6、可重复读【Repeatable Read】

  • 终端 A


  • 终端 B

在终端 B commit 之前可以看到, 事务无论什么时候进行查找,看到的结果都是一致的,这叫做可重复读

如果将上面的终端 A 中的 update 操作,改成 insert 操作,会有什么问题?
  • 终端 A


  • 终端 B

select * from account;  多次查看,发现终端  在对应事务中  insert  的数据在终端  的事务周期中,也没有什么影响,也符合可重复的特点。但一般的数据库在可重复读情况的时候,无法屏蔽其他事务 insert  的数据。
为什么?
因为隔离性实现是对数据加锁完成的,而 insert  待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题, 会造成虽然大部分内容是可重复读的,但是 insert  的数据在可重复读情况被读取出来,导致多次查找时会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读(phantom read)
很明显, MySQL  在  RR  级别的时候,是解决了幻读问题的( 解决的方式是用 Next-Key 锁( GAP+ 行锁) 解决的。

 7、串行化【serializable】 

对所有操作全部加锁,进行串行化不会有问题,但是只要串行化,效率就很低,几乎完全不会被采用。

  • 终端 A 


  • 终端 B


8、总结

  • 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。
  • 不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了 幻读的重点在于新增:同样的条件在第 次和第 次读出来的记录数不一样。
  • 说明:MySQL 默认的隔离级别是可重复读,一般情况下不要修改。
  • 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有 commit 的时候,影响会比较大。


六、一致性(Consistency)

  • 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。
  • 其实一致性和用户的业务逻辑强相关,一般 MySQL 提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是一致性是由用户决定的。
  • 而技术上,通过 AID 保证 C。

七、扩展学习(了解)

如何实现事务的隔离性-CSDN博客

Innodb 中的事务隔离级别和锁的关系-CSDN博客

Mysql 间隙锁原理,以及 Repeatable Read 隔离级别下可以防止幻读原理-CSDN博客


在 RR 级别的时候,多个事务的 update,多个事务的 insert,多个事务的 delete,是否会有加锁现象?
现象结果是, update insert delete  之间是会有加锁现象的,但是  select  和这些操作是不冲突的。这就是通过读写锁(锁有行锁 / 表锁) + MVCC  完成隔离性。

八、如何理解隔离性(深度)

数据库并发的场景有三种:

  • - :不存在任何问题,也不需要并发控制。
  • 读-写 有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读。
  • - :有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失(后面补充)

 1、读-写 

多版本并发控制( MVCC 是一种用来解决 -写冲突 无锁并发控制
为事务分配单向增长的事务 ID,为每个修改保存一个版本,版本与事务  ID  关联,读操作只读该事务开始前的数据库的快照。 所以 MVCC 可以为数据库解决以下问题:
  • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
  • 同时还可以解决脏读、幻读、不可重复读等事务隔离问题,但不能解决更新丢失问题。
  • 每个事务都要有自己的事务 ID,可以根据事务 ID 的大小来决定事务到来的先后顺序。
  • mysqld 可能会面临处理多个事务的情况,事务也有自己的生命周期,mysqld 要对多个事务进行管理,先描述,再组织。事务在我看来,mysqld 中一定是对应的一个或者一套结构体对象 / 类对象,事务也要有自己的结构体。
理解 MVCC 需要知道三个前提知识:
  • 个记录隐藏字段
  • undo 日志
  • Read View

(1)个记录隐藏列字段
  • DB_TRX_ID6 byte,最近修改(修改 插入)事务 ID记录创建这条记录 最后一次修改该记录的事务 ID
  • DB_ROLL_PTR7 byte,回滚指针,指向这条记录的上一个版本(简单理解成指向历史版本就行,这些数据一般在 undo log 中)。
  • DB_ROW_ID6 byte隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以 DB_ROW_ID 产生一个聚簇索引。

补充:实际还有一个删除 flag 隐藏字段,既记录被更新或删除并不代表真的删除,而是删除 flag 变了

假设测试表结构是:
上面描述的意思是:
目前并不知道创建该记录的事务  ID ,隐式主键,我们就默认设置 成 null 1 。第一条记录也没有其他版本,我们设置回滚指针为 null

(2)undo 日志
MySQL 将来是以服务进程的方式,在内存中运行。
之前所学的所有机制:索引、事务、隔离性、日志等都是在内存中完成的,即在 MySQL 内部的相关缓冲区中保存相关数据,完成各种判断操作。然后在合适的时候将相关数据刷新到磁盘当中的。
所以,理解  undo log   简单理解成就是 MySQL 中的一段 内存缓冲区 ,用来保存日志数据的就行。

(3)模拟 MVCC
现在有一个事务  10 ,对  student  表中记录进行修改( update): 将  name( 张三 改成  name( 李四 )
  • 事务 10 因为要修改,所以要先给该记录加行锁
  • 修改前,现将改行记录拷贝到 undo log 中。所以,undo log 中就有了一行副本数据。(原理就是写时拷贝)
  • 所以现在 MySQL 中有两行同样的记录。现在修改原始记录中的 name,改成 '李四',并且修改原始记录的隐藏字段 DB_TRX_ID 为当前 事务 10 的 ID,我们默认从 10 开始,之后递增。而原始记录的回滚指针 DB_ROLL_PTR 列,里面写入 undo log 中副本数据的地址,从而指向副本记录,表示我的上一个版本就是它。
  • 事务 10 提交,释放锁 

(此时,最新的记录是 ' 李四'   那条记录)
现在又有一个事务  11 ,对  student  表中记录进行修改( update) :将  age(28)  改成  age(38)
  • 事务 11 因为也要修改,所以要先给该记录加行锁。
  • 修改前,现将改行记录拷贝到 undo log 中。所以,undo log 中就又有了一行副本数据。此时,新的副本我们采用头插方式,插入 undo log
  • 现在修改原始记录中的 age 改成 38,并且修改原始记录的隐藏字段 DB_TRX_ID 为当前事务 11 的 ID。而原始记录的回滚指针 DB_ROLL_PTR 列里面写入 undo log 中副本数据的地址,从而指向副本记录,既表示我的上一个版本就是它。
  • 事务11提交,释放锁。

这样,就有了一个基于链表记录的历史版本链。所谓的回滚无非就是用历史数据覆盖当前数据 

上面的一个个版本,我们可以称之为一个个的 快照

【思考】
上面是以更新(upadte)主讲的,如果是 delete 呢?
一样的,别忘了,删数据不是清空,而是设置  flag  为删除即可,也可以形成版本。

如果是 insert 呢?
因为  insert  是插入,也就是之前没有数据,那么  insert  也就没有历史版本。但是一般为了回滚操作,insert  的数据也是要被放入  undo log  中,如果当前事务  commit  了,那么这个  undo log 的历史  insert  记录就可以被清空了。
总结:也就是可以理解成  update  和  delete  可以形成版本链, insert  暂时不考虑。

那么 select 呢?
select  不会对数据做任何修改,所以为  select  维护多版本没有意义。

此时有个问题,就是 select 读取,是读取最新的版本呢?还是读取历史版本?
  • 当前读:读取最新的记录,就是当前读。增删改,都叫做当前读,select 也有可能当前读,比如:select lock in share mode(共享锁),select for update。
  • 快照读:读取历史版本(一般而言),就叫做快照读。(这个后面重点讨论)
可以看到,在多个事务同时删改查时都是当前读,是要加锁的。那同时有  select  过来,如果也要读取最新版( 当前读) ,那么也就需要加锁,这就是串行化。
但如果是快照读,读取历史版本的话,是不受加锁限制的,也就是可以并行执行。换而言之,提高了效率,即  MVCC  的意义所在。

那么是什么决定了 select 是当前读还是快照读呢?

隔离级别。


那为什么要有隔离级别呢?
事务都是原子的。所以无论如何,事务总有先有后。
但是经过上面的操作可以发现,事务从  begin->CURD->commit  是有一个阶段的,也就是事务有执行前,执行中,执行后的阶段。但不管怎么启动多个事务,总是有先有后的。
那么多个事务在执行中的  CURD  操作是会交织在一起的。那为了保证事务的  有先有后 ,是不是应该让不同的事务看到它该看到的内容,这就是所谓的隔离性与隔离级别要解决的问题。

先来的事务应不应该看到后来的事务所做的修改呢? 那么如何保证不同的事务看到不同的内容呢?也就是如何实现隔离级别?


(4)Read View
Read View   就是事务进行 快照读 操作的时候生产的 读视图 Read View) ,在该事务执行的快照读的那一刻会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID( 当每个事务开启时都会被分配一个  ID, 这个  ID  是递增的,所以最新的事务 ID  值越大)
Read View MySQL 源码中 就是一个 ,本质是用来进行可见性判断的。 即当我们某个事务执行快照读的时候,对该记录创建一个 Read View 读视图,把它比作条件 用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的 undo log 里面的某个版本的数据。

下面是简化过的 ReadView 结构:

class ReadView {
    // ...

private:
    // 高水位,大于等于这个ID的事务均不可见
    trx_id_t m_low_limit_id

    // 低水位:小于这个ID的事务均可见
    trx_id_t m_up_limit_id;

    // 创建该 Read View 的事务ID
    trx_id_t m_creator_trx_id;

    // 创建视图时的活跃事务id列表
    ids_t m_ids;

    // 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG
    // 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG
    trx_id_t m_low_limit_no;

    // 标记视图是否被关闭
    bool m_closed;
    
    // ...
};
m_ids;          // 一张列表,用来维护Read View生成时刻,系统正活跃的事务ID

up_limit_id;    // 记录m_ids列表中事务ID最小的ID

low_limit_id;   // ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1

creator_trx_id; // 创建该ReadView的事务ID
我们在实际读取数据版本链的时候,是能读取到每一个版本对应的事务  ID  的,即当前记录的  DB_TRX_ID
那我们现在手里面有的东西就有,当前快照读的 ReadView 和 版本链中的某一个记录的 DB_TRX_ID
所以现在的问题就是,当前快照读应不应该读到当前版本记录。(下图可解决该问题)

Read View 是事务可见性的一个类,不识事务创建出来就有的,而是当这个事务(已经存在)首次进行快照读时,MySQL 形成的。

对应源码策略:  

如果查到不应该看到当前版本,接下来就是遍历下一个版本,直到符合条件就可以看到。上面的  readview 是当你进行 select  时会自动形成。

(5)整体流程
  • 假设当前有条记录:
  •  事务操作:

事务  4 :修改  name( 张三 ) 变成  name( 李四 )。
事务  2 对某行数据执行了 快照读 ,数据库为该行数据生成一个 Read View 读视图。
// 事务2的 Read View
m_ids;          // 1, 3
up_limit_id;    // 1
low_limit_id;   // 4+1=5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID
creator_trx_id; // 2
  • 此时版本链是:  

  • 只有事务  修改过该行记录,并在事务  执行快照读前,就提交了事务。
  • 事务 在快照读该行记录时会拿该行记录的 DB_TRX_ID 去跟 up_limit_id,low_limit_id 和活
    跃事务  ID  列表 (trx_list) 进行比较,判断当前事务  能看到该记录的版本。
// 事务2的 Read View
m_ids;          // 1, 3
up_limit_id;    // 1
low_limit_id;   // 4+1=5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID
creator_trx_id; // 2

// 事务4提交的记录对应的事务ID
DB_TRX_ID=4

// 比较步骤
DB_TRX_ID(4)< up_limit_id(1) ? 不小于,下一步
DB_TRX_ID(4)>= low_limit_id(5) ? 不大于,下一步
m_ids.contains(DB_TRX_ID) ? 不包含,说明,事务4不在当前的活跃事务中。

// 结论
事务4的更改应该看到。
所以事务2能读到的最新数据记录是事务4所提交的版本,而事务4提交的版本也是全局角度上最新的版本

(6)RR 与 RC 的本质区别
a. 当前读和快照读在 RR 级别下的区别
select * from user lock in share mode 以加共享锁方式进行读取,对应的就是当前读。
  • 测试用例1 - 1 

  • 测试用例2 - 2

  • 用例 与用例 唯一区别仅仅是表 的事务 在事务 修改 age 快照读过一次 age 数据。
  • 表 的事务 在事务 修改 age 前没有进行过快照读。

【结论】

  • 事务中快照读的结果是非常依赖该事务首次出现快照读的地方,即某个事务中首次出现快照读,决定该事务后续快照读结果的能力 delete 也同样如此

【总结 —— RR RC 的本质区别

  • 正是 Read View 生成时机的不同,从而造成 RC 和 RR 级别下快照读的结果的不同。
  • 在 RR 级别下的某个事务的对某条记录的第一次快照读会创建一个快照及 Read View 将当前系统活跃的其他事务记录起来。
  • 此后在调用快照读时,使用的还是同一个  Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个 Read View,所以对之后的修改不可见。
  • 即 RR 级别下,快照读生成 Read View 时,Read View 会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于 Read View 创建的事务所做的修改均是可见的。
  • 而在 RC 级别下的,事务中,每次快照读都会新生成一个快照和 Read View,这就是我们在 RC 级别下的事务中可以看到别的事务提交的更新的原因。
  • 总之在 RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;而在 RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View,之后的快照读获取的都是同一个 Read View
  • 正是 RC 每次快照读,都会形成 Read View,所以 RC 才会有不可重复读问题。

2、-读

不讨论。

 3、写-写  

现阶段直接理解成都是当前读,这里不做深究。

4、推荐阅读

【MySQL笔记】正确的理解MySQL的MVCC及实现原理_mysqlmvcc实现原理-CSDN博客

详细分析MySQL事务日志(redo log和undo log) - 骏马金龙 - 博客园 (cnblogs.com)

【MySQL】InnoDB 如何避免脏读和不可重复读_innodb怎么解决脏读-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/427897.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DCTNet

DCTNet http://giantpandacv.com/academic/%E7%AE%97%E6%B3%95%E7%A7%91%E6%99%AE/%E9%A2%91%E5%9F%9F%E4%B8%AD%E7%9A%84CNN/CVPR%202020%20%E5%9C%A8%E9%A2%91%E5%9F%9F%E4%B8%AD%E5%AD%A6%E4%B9%A0%E7%9A%84DCTNet/ 一个对输入图像进行频域转换和选择的方法&#xff0c;达到…

Timeout while connecting to “172.168.252.245:161

Timeout while connecting to “172.168.252.245:161” 现象 排查过程 交换机型号H3C&#xff0c;交换机采用SNMPV3协议对接zabbix&#xff0c;交换机配置如下 snmp-agent sys-info version all snmp-agent group v3 zabbix_group privacy read-view isoview snmp-agent …

本地安装部署Flask并结合内网穿透实现远程访问本地web界面

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

windows下的反调试探究——调用API

NtGlobalFlag 在 32 位机器上&#xff0c;NtGlobalFlag字段位于PEB的0x68的偏移处&#xff0c;64 位机器则是在偏移0xBC位置&#xff0c;该字段的默认值为 0。当调试器正在运行时&#xff0c;该字段会被设置为一个特定的值 该字段包含有一系列的标志位&#xff0c;由调试器创…

(学习日记)2024.03.02:UCOSIII第四节:创建任务

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

【MySQL 系列】在 Windows 上安装 MySQL

在 Windows 平台上安装 MySQL 很简单&#xff0c;并不需要太复杂的步骤。按照本文的步骤操练起来就可以了。 文章目录 1、下载 MySQL 安装程序2、安装 MySQL 数据库2.1、选择安装类型2.2、检查所需组件2.3、安装所选产品组件2.4、产品配置2.5、配置高可用性2.6、配置服务器类型…

UDP协议和TCP协议详解

文章目录 应用层自定义协议 传输层udp协议TCP协议1.确认应答2.超时重传3.连接管理建立连接, 三次握手断开连接, 四次挥手tcp的状态 4.滑动窗口5.流量控制6.拥塞控制7.延时应答8.携带应答9.面向字节流10.异常情况 应用层 自定义协议 客户端和服务器之间往往要进行交互的是“结构…

网络工程师笔记8

华为VRP系统 设备管理方式 web管理方式 命令行管理方式 修改命令&#xff1a;undo 基础配置命令

学习python时一些笔记

1、winr 命令提示符的快捷键 输入cmd进入终端 2、在终端运行桌面上的python文件 cd desktop(桌面) cd是进入该文件夹的意思。 cd .. 回到上一级 运行python时一定要找到文件的所在地 输入python进入&#xff0c;exit()退出%s字符串占位符%d数字占位符%f浮点数占位符input输…

【Python】变量的引用

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

KMP算法和Manacher算法

KMP算法 KMP算法解决的问题 KMP算法用来解决字符串匹配问题: 找到长串中短串出现的位置. KMP算法思路 暴力比较与KMP的区别 暴力匹配: 对长串的每个位,都从头开始匹配短串的所有位. KMP算法: 将短字符串前后相同的部分存储在 n e x t next next数组里,让之前匹配过的信息指…

如何利用pynlpir进行中文分词并保留段落信息

一、引言 nlpir是由张华平博士开发的中文自然处理工具&#xff0c;可以对中文文本进行分词、聚类分析等&#xff0c;它既有在线的中文数据大数据语义智能分析平台&#xff0c;也有相关的python包pynlpir&#xff0c;其github的地址是&#xff1a; Pynlpir在Github上的地址 这…

算法(6)——模拟

一、什么是模拟 模拟是对真实事物或者过程的虚拟。在编程时为了实现某个功能&#xff0c;可以用语言来模拟那个功能&#xff0c;模拟成功也就相应地表示编程成功。 二、模拟算法的思路 模拟算法是一种基本的算法思想&#xff0c;可用于考查程序员的基本编程能力&#xff0c;…

抖店入驻费用是多少?新手入驻都有哪些要求?2024费用明细!

我是电商珠珠 我做电商做了将近五年&#xff0c;做抖店做了三年多&#xff0c;期间还带着学员一起做店。 今天&#xff0c;就来给大家详细的讲一下在抖音开店&#xff0c;需要多少费用&#xff0c;最低需要投入多少。 1、营业执照200元左右 就拿个体店举例&#xff0c;在入…

二叉搜索树题目:将有序数组转换为二叉搜索树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法证明代码复杂度分析 题目 标题和出处 标题&#xff1a;将有序数组转换为二叉搜索树 出处&#xff1a;108. 将有序数组转换为二叉搜索树 难度 4 级 题目描述 要求 给定整数数组 nums \texttt{nums}…

大辩论:人工智能时代人类和软件的未来

关于人工智能将在多大程度上接管软件开发、交付和支持任务及其对就业的影响&#xff0c;聆听双方的争论&#xff0c;对于技术来说既令人兴奋&#xff0c;又让人类感到恐惧。争论是这样的&#xff1a; 人工智能倡导者&#xff1a;欢迎来到未来&#xff01;凭借当今人工智能的能…

猫挑食不吃猫粮怎么办?可以解决猫咪挑食的主食冻干推荐

现在的猫奴们普遍将自家的小猫视为掌上明珠&#xff0c;宠爱有加。然而&#xff0c;这种宠爱有时也会导致猫咪养成一些不良习惯&#xff0c;比如挑食。猫挑食不吃猫粮怎么办&#xff1f;今天为大家分享一个既不让咱宝贝猫咪受罪又可以改善猫咪挑食的方法。 一、猫咪是为什么挑食…

(C语言)qsort函数详解

目录 1. qsort解释 2. qsort实例 2.1 qsort排列整形数组类型&#xff1a; 2.2 qsort排列结构体类型数据&#xff08;字符串&#xff09;&#xff1a; 2.3 qsort排列结构体类型数据&#xff08;整形&#xff09;&#xff1a; 1. qsort解释 我们可以进入网站&#xff1a;qso…

第一天 走进Docker的世界

第一天 走进Docker的世界 介绍docker的前世今生&#xff0c;了解docker的实现原理&#xff0c;以Django项目为例&#xff0c;带大家如何编写最佳的Dockerfile构建镜像。通过本章的学习&#xff0c;大家会知道docker的概念及基本操作&#xff0c;并学会构建自己的业务镜像&…
最新文章