当前位置: 首页 > article >正文

【MySQL-7】事务

目录

1. 整体学习思维导图

2. 什么是事务

2.1 事务的概念

2.2 事务的属性(ACID)

2.3 事务出现的原因

2.4 查看存储引擎对事务的支持

3. 事务的使用

3.1 事务的提交方式

3.1.1 手动提交

3.1.2 自动提交

结论:

3.2 事务的隔离级别

3.2.1 理解隔离

3.2.2 设置隔离级别

3.2.3 隔离级别

读未提交(Read Uncommitted)

读提交(Read Committed)

可重复读(Repeatable Read)

串行化(Serializable)

总结:

4. 隔离性和隔离级别的理解

4.1 数据库的并发场景

4.2 读-写场景并发(MVCC)理解

4.2.1 事务ID

4.2.2 三个隐藏记录字段

4.2.3 undo日志

模拟MVCC:

探讨:

4.3 当前读和快照读

4.3.1 Read View

4.4 RR与RC的区别:


1. 整体学习思维导图

2. 什么是事务

2.1 事务的概念

事务是从应用层面上来看待的,比如在一个同学退学了,我们需要在学校的教务系统的数据库中将该同学的信息,选课,成绩都要删除掉,这需要一系列的SQL语句,而我们就把这个处理的DML语句集合称作为一个事务!

2.2 事务的属性(ACID)

  • 原子性(Atomicity):一个事务的所有操作要么全部执行,要么全部未执行,不能出现中间的状态。就拿前面的比方同学退学,我们的退学事务不能只说删除同学的信息,但不去删除选课和成绩!如果一个事务在执行过程中发生错误,那么该事务就会回滚(rollback)到没执行的状态!

  • 一致性(Consistency):事务的执行结果是可以预期的,比如A向B转账50,那么A的账户会减少50,B的账户会增加50,A向B转账的过程就是一个事务,而这个事务的结果是可以预期的就称作为一致性。MySQL对于一致性并没有做过多的设计,MySQL是通过AID来保证C一致性的,简单说AID是因,C是果。

  • 隔离性(Isolation):每个事务执行的期间是隔离的,数据库允许多个并发的事务对数据进行读写操作,隔离性可以防止多个事务在读写数据交叉导致数据的不一致。

    • 隔离性的级别(根据隔离影响划分)

    • 读未提交(Read UnCommitted)

    • 读提交(Read Committed)

    • 可重复读(repeatable read)

    • 串行化(Serializable)

  • 持久性(Durability):事务处理结束之后,对于数据的修改是永久性的,即使系统故障也不会丢失。

查看事务隔离级别:

查看全局:

mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ       |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

 查看当前会话:

mysql> select @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| REPEATABLE-READ        |
+------------------------+
1 row in set, 1 warning (0.00 sec)

查看默认: 

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

2.3 事务出现的原因

事务的本质是一系列的DML语句,但是我们在应用层编写时不可能时常去注意细节,我们可以用面向对象的思想来解释,而事务就相当于一个对象,它将DML语句描述后组织起来。

我们还将MySQL中的一条信息称作为一条记录。

2.4 查看存储引擎对事务的支持

mysql> show engines \G;
*************************** 1. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES     -- 对事务支持
          XA: YES
  Savepoints: YES
*************************** 2. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO     -- 对事务不支持
          XA: NO
  Savepoints: NO

3. 事务的使用

3.1 事务的提交方式

  • 手动提交

  • 自动提交

3.1.1 手动提交

我们先创建一个测试表:

create table if not exists T_TB( 
    id int primary key comment'编号', 
    name varchar(20) default'', 
    age tinyint  
);

手动提交和自动提交互不影响,下面是手动提交的开启/结束: 

begin/start transaction
commit;

手动创建回滚点: 

mysql> savepoint save1; Query OK, 0 rows affected (0.00 sec)-- 创建一个保存点save1
mysql> rollback to save1; -- 回滚到保存点save1 

  • 如果手动开始的事务没有提交,程序崩溃后会自动回滚;手动开始事务提交后即使程序崩溃也会持久化保存

  • 自动提交的开启是否不影响手动提交!

3.1.2 自动提交

查看自动提交是否开启:OFF(没有开启)/ON(开启)

mysql> show variables like'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

自动提交开启后,我们正常进行一条条CURD操作都是一个个事务,即使程序异常崩溃也会持久化保存;如果关闭自动提交进行CURD操作,我们程序异常崩溃后会回滚!

所以操作能否对数据进行持久化的影响取决于是否提交了!

结论:

 

3.2 事务的隔离级别

3.2.1 理解隔离

  • 隔离性:数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征隔离性。

  • 隔离级别:数据库中,允许事务受不同程度的干扰,就有了一种重要特征隔离级别 。

3.2.2 设置隔离级别

我们前面讲了如何查看隔离级别,这边我们来看如何设置隔离级别:

--设置
-- 设置当前会话 or 全局隔离级别语法
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED(读未提交) | READ
COMMITTED(读提交) | REPEATABLE READ(可重复读) | SERIALIZABLE(串行化)}  
  • 当前会话:只作用于这一次会话,一旦退出就消失!

  • 全局:更新完全局隔离级别需要重启MySQL才会生效!

3.2.3 隔离级别

读未提交(Read Uncommitted)

在该隔离级别下,两个事务并发读写数据,其中一方事务进行读操作,另一方事务进行写操作读操作的事务可以实时看到写操作事务对数据的修改(即使写操作事务并没有进行提交),我们将读操作事务读取到的数据称作为脏读(因为写操作事务没有提交cmmit,我们是不知道读取的数据是否会回滚rollback)!

读提交(Read Committed)

在该隔离级别下,两个事务并发读写数据时,任何一方想看到另外一方的修改需要等对方提交才可以,但是它会带来一个问题--不可重复度,不可重复读是指原本我们的数据内容只有三条记录,我们第一次读取也是三条,与此同时另一个事务进行了insert并且结束了事务,我们这边的事务又进行了一次查询发现表中的数据改变成了四条,与前面的三条不相符,我们将这种现象称作为不可重复读

可重复读(Repeatable Read)

在该隔离级别下,两个事务并发读写数据时,任何一方在事务过程中都不会影响到另一个事务,即使第一个事务已经结束DML操作,但是第二个事务是无法看到进过操作后的表。只有双方都结束并且commit,才可以看到对方的修改。

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

串行化(Serializable)

在该隔离级别下,两个事务并发读写数据时,两个事务就需要进行排队执行,只有在对方提交完成后另一方才可以进行相应的操作(读取数据不受影响)。

 我们可以看见更新SQL语句卡住了。

 当我们右边事务提交后,卡住的SQL执行成功!

 

总结:
  • 隔离级别越高,安全性越好,但是数据库的并发性能就会降低,我们需要根据需求找到一个平衡点。

  • 不可重复读重点在于修改和删除

  • 幻读的重点在于新增的数据

4. 隔离性和隔离级别的理解

4.1 数据库的并发场景

  • 读-读:不存在问题

  • 读-写:存在问题,可能会出现(脏读/幻读/不可重复读)

  • 写-写:存在问题

4.2 读-写场景并发(MVCC)理解

我们先来理解数据库中出现并发场景最多的读-写场景。

多版本并发控制(MVCC)是一种解决读-写问题的无锁并发控制。

在理解MVCC之前我们需要来学习一些前置知识点:

  1. 三个隐藏记录字段

  2. undo日志

  3. Read View

4.2.1 事务ID

每个事务都要有自己的ID,ID决定他们到来的先后顺序。

MySQL可能有时并发的处理多个事务,事务也就有了自己的生命周期,那么我们就需要对事务进行先描述在组织,通过一个对象或者结构体将事务管理起来!

4.2.2 三个隐藏记录字段

  • DB_TRX_ID:称作为最近修改事务ID,记录创建这条记录/最后一次修改(修改/插入)该记录的事务ID 。

  • DB_ROLL_PTR: 称作为回滚指针,用于指向该条记录的上个版本。

  • DB_ROW_ID:隐含的自增ID(隐藏主键),如果数据表没有主键, InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引

补充:还有一个flag字段用于表示该条记录是否删除,比如说1表示删除,0表示存在。记录的更新和删除不一定是真的删除了!

-- 我们创建一个测试表,只有姓名和年龄
mysql> create table if not exists T_MVCC(
    -> name varchar(15),
    -> age int unsigned
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> insert into T_MVCC values('张三', 18);
Query OK, 1 row affected (0.00 sec)

mysql> select * from T_MVCC limit 1;
+--------+------+
| name   | age  |
+--------+------+
| 张三   |   18 |
+--------+------+
1 row in set (0.00 sec)

我们将隐藏的字段也添加上,DB_TRX_ID默认null,DB_ROLL_PTR默认null,DB_ROW_ID默认1。 

name

age

DB_TRX_ID

DB_ROLL_PTR

DB_ROW_ID

张三

18

null

null

1

4.2.3 undo日志

我们需要知道MySQL数据库在我们对数据进行的操作短时内都是在内存中执行的,根据算法过一定的时间或者满足一定的条件,数据才会被从内存向磁盘上写入!

而undo log就是存放在内存缓冲区用于日志信息!

模拟MVCC:

  1. 前提条件:我们需要将张三的age修改为20(update)。

在事务ID: 1修改前,给该条记录加上行锁,然后拷贝一份旧版本到undo log中,等待事务1提交后,解锁。修改后的事务ID: 1中的PTR指向上个版本,这样可以方便进行回滚操作!

而我们可以将undo log中的版本称作为一个个快照!

探讨:

  • 对于删除delete,我们前面介绍过flag,所以删除也可以形成一个版本进行存放,在执行删除操作时,内部存放的是与之相反的添加的SQL,一旦回滚就执行该SQL。

  • 对于插入insert,insert插入的是之前版本没有的数据,按前面来看insert是无法形成一个旧版本的,但是为了回滚操作,insert的数据也要被存放到undo log中,只有当commit后,insert存到的数据才会被清空!

  • 对于select呢?我们什么时候读当前最新的数据(当前读)还是去读取旧数据(快照读)呢?我们下面来详细看看:

4.3 当前读和快照读

控制当前读还是快照读,取决于隔离级别!我们虽然说事务的属性是原子性的,但是在MySQL处理事务的过程中也是存在先后的顺序,而这个顺序将决定读取数据的版本和范围!

可以简单说当前读还是快照读,一个事务该读取那些版本的数据,也就是隔离级别实现的本质。

4.3.1 Read View

  • Read View就是事务进行 快照读 操作的时候生产的 读视图 (Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)

  • Read View 在 MySQL 源码中,就是一个类,本质是用来进行可见性判断的。 我们创建一个事务的时候不会创建Read View, 只有当我们某个事务执行快照读(select)的时候,对该记录创建一个 Read View 读视图,把它比作条件,用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的 undo log 里面的某个版本的数据。

Read View类的主要成员变量

m_ids;         // 相当于一张列表记录当前活跃的事务的ID
up_limit_id;   // 用于记录m_ids表中最小的事务ID
low_limit_id;  // 用于记录所有事务中(包括已经commit的)最大的ID值+1
creator_trx_id //创建该ReadView的事务ID

通过上图:

在m_ids表中的ID存在: 1 2 3

up_limit_id:1

low_limit_id: 5

creator_trx_id: 2

事务4修改操作后,id是不存在于m_ids,并且也不大于low_limit_id,快照读是可见事务4的版本。

4.4 RR与RC的区别:

  • select * from user lock in share mode ,以加共享锁方式进行读取,对应的就是当前读,该条语句可以读到最新的版本。

RR: 一个Read View用到底 RC: 每次快照读都会更新Read View

比方说我们现在存在着事务A,事务B:

 

 

  • 我们先以RR做举例:事务B在快照读时生成的Read View中的m_ids中存放着事务A的ID,所以事务B是看不见事务A的修改版本,即使提交后,由于RR一个Read View用到底的原因,AID还在m_ids依旧不可见!

  • 反观RC,每次更新Read View,虽然第一次事务A的ID在m_ids中不可见其版本,但是后续提交后再次快照读生成新的Read View事务A的ID不存在m_ids并且满足查看的条件,所以快照读的版本就是事务A的版本。


http://www.kler.cn/a/523838.html

相关文章:

  • mysql_init和mysql_real_connect的形象化认识
  • 青少年编程与数学 02-008 Pyhon语言编程基础 07课题、数字
  • 16、智能驾驶域控的材料回收
  • nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
  • 大一计算机的自学总结:异或运算
  • 深度学习中常用的评价指标方法
  • 【WebGL】纹理
  • 【某大厂一面】java深拷贝和浅拷贝的区别
  • 顶刊JFR|ROLO-SLAM:首个针对不平坦路面的车载Lidar SLAM系统
  • 基于Python的智慧物业管理系统
  • aws sagemaker api 获取/删除 endpoints
  • ResNeSt: Split-Attention Networks论文学习笔记
  • MATLAB基础应用精讲-【数模应用】DBSCAN算法(附MATLAB、R语言和python代码实现)(二)
  • 54.数字翻译成字符串的可能性|Marscode AI刷题
  • Next.js 14 TS 中使用jwt 和 App Router 进行管理
  • 基于 NodeJs 一个后端接口的创建过程及其规范 -- 【elpis全栈项目】
  • oracle比较一下统计信息差异吧
  • Vue 响应式渲染 - 列表布局和v-html
  • 【2024年华为OD机试】(C卷,200分)- 推荐多样性 (JavaScriptJava PythonC/C++)
  • kaggle-ISIC 2024 - 使用 3D-TBP 检测皮肤癌-学习笔记
  • go 循环处理无限极数据
  • 【llm对话系统】大模型 RAG 之回答生成:融合检索信息,生成精准答案
  • HTML表单深度解析:GET 和 POST 提交方法
  • linux监控脚本+自动触发邮件发送
  • 【AI】【本地部署】OpenWebUI的升级并移植旧有用户信息
  • 面向对象编程 vs 面向过程编程