MySQL学习记录——십이 事务

文章目录

  • 1、了解事务
  • 2、事务提交
  • 3、事务隔离级别
    • 1、隔离性和隔离级别
    • 2、查看、设置隔离级别
    • 3、读未提交
    • 4、读提交
    • 5、可重复读
    • 6、串行化
    • 7、总结
  • 4、事务一致性
  • 5、事务隔离性
    • 1、隐藏字段
    • 2、undo日志
    • 3、模拟MVCC
    • 4、Read View
  • 6、读提交RC、可重复读RR的区别


1、了解事务

MySQL内部是用多线程实现的。事务就是多个mysql语句组成的。对于用户来说这是事务,比如要查找一下以前的消费记录,要转账等,对于程序员就是多个mysql语句。事务有4个特性

在这里插入图片描述
在这里插入图片描述

4个特性统称ACID。事务并不是数据库自己有的,而是因为应用层的需求而存在的。

show engines能查看当前支持的搜索引擎,只有innodb支持事务。

事务有自、手动提交方式,可用show variable like 'autommit’来看,默认是自动提交。修改成手动提交。

set autocommit=0;

2、事务提交

为了操作事务后能够方便地看到,先把隔离级别设置成读未提交。

set global transaction isolation level READ UNCOMMITTED;//可以小写

设置好后重登一下mysql就行。查看一下

select @@tx_isolation;

查看当前有多少客户端在访问数据库

show processlist;

创建一个表用来作例子。

create table if not exists account( id int primary key, name varchar(50) not null default '', blance decimal(10,2) not null default 0.0 )ENGINE=InnoDB DEFAULT CHARSET=UTF8;

看一下当前事务提交方式

show variables like 'autocommit';

启动事务

//两种
start transaction;
begin;

开两个客户端并发访问mysql服务器。

设置一个保存点

savepoint 名字;

保存点就相当于一个位置,可以回滚到这个位置。

插入一些数据,插入之中可以再多设置一些保存点。

在这里插入图片描述

回滚到s3位置。

rollback to s3;

在这里插入图片描述

结束事务,提交事务。结束时会保存最后一次操作后的表的内容,永久。即使结束后又回滚。回滚只在事务运行期间才能回滚。

commit;

这时候再select * 会看到是最后一次操作后的表内容。如果没有保存点输入rollback就会直接回滚到最一开始,也就是数据全没了。

如果事务运行过程中,插入了数据,但是没commit,而是异常退出或者服务端退出,那就会自动回滚,插入的数据就没有插入。

默认情况下,autocommit是ON的,被开启的,但如果我们不手动commit就不会提交。autocommit不影响这个,因为我们是手动begin,手动begin就得手动commit,和autocommit没关系。

像之前写的mysql语句,并没有begin和commit但也能保存下来插入的内容,是因为默认autocommit是ON的,所以自动打开事务,退出时自动提交。如果本身是ON,在事务运行过程中变成OFF,那么得commit才能提交所有的变更。

3、事务隔离级别

1、隔离性和隔离级别

MySQL必然有多个事务同时进行,状态各自不同,最重要的就是执行中的事务不被受影响。每个事务都要看到它运行时看到的数据,而不是一定要新数据。假如有更新和读取两个事务,读取先发生,那就读取,更新后发生,那就更新,而不是读取一定要读最新的数据,这其实就是事务被隔离起来了。比如转账和查看余额,转账后,余额才能显示新数字,不转,就看不到。隔离是必要的,隔离是保证执行中的多个事务互相隔离,互不影响。隔离级别决定了隔离的程度。

MySQL有四种隔离级别,读未提交RU,读提交RC,可重复读RR,串行化S,默认为可重复读,最高为串行化。

读未提交:两个事务并发运行,一个事务更改数据,没提交,另一个事务能看到变更。

读提交:更改完提交后,其它事务才能看到。

可重复读:甲乙事务必须都提交结束,乙再新起一个事务才能查看到甲事务的数据变更,而在两者都未结束时,谁都不能看到对方的更改。

串行化:一个事务结束后另一个事务才能开始运行,没结束就都在等待,也就是很多个事务都只能等一个事务结束。

上面的隔离级别都是关于CURD的,是关于读写的,这四个并不适用于数据库所有的操作。

2、查看、设置隔离级别

查看

//查看全局隔离级别
select @@global.tx_isaolation;
//查看会话(当前)全局隔离级别
select @@session.tx_isolation;
//同上
select @@tx_isolation;

登录mysql后,会默认拷贝全局隔离级别到当前会话,如果改会话的级别,只影响会话,如果改变全局,那么以后的每次登录都会被改变隔离级别。

设置隔离级别

set sessionglobal transaction isolation level 隔离级别;
//例子
set session transaction isolation level {read committed};

设置完后可以重登一下。

3、读未提交

先设置全局的为read-uncommitted,再手动启动事务。开两个窗口去访问mysql。begin后,一个客户端插入数据,另一个客户端就会查看到。让插入数据的客户端回滚到最一开始,另一个客户端此时就查看不到刚才插入的数据。

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

4、读提交

全局改成读提交read committed。读提交是当前事务提交后,其它事务才能看到变更,无论其它事务是否结束。因为这样的特性,有可能两次select看到不一样的结果,结果会影响上层决策,这就是不可重复读的特性。

这里的问题就是一个事务提交了,其它事务即使在运行中也能看到新的变更,这是不是没有保证原子性?应该让正在运行的事务看不到,并让它们结束,再起一个事务后才看到新的变更。所以这个读提交同读未提交一样,都不推荐使用。

5、可重复读

mysql默认级别,repeatable read。事务在修改不会影响其它事务的运行。可以开两个窗口,两个客户端访问同一个表,一个事务插入,另一个事务查看。事务之间不影响,这也就是可重复读的特性。

RR级别的多个事务的更新、增加、删除都是加锁的。

一般的数据库下,无法屏蔽其它事务的insert操作,隔离性难以实现,这是因为各理性是对数据加锁来完成的,insert插入的数据并不存在,加锁无法屏蔽这类问题。所以这就会导致,即使可重复读,inset的数据在多次查找时会被查找出来,这就是幻读,在RC、RU、RR级别的问题。而MySQL解决了这个问题,是用过Next-Key锁来解决的。

6、串行化

全局设置serializable,同样可以开两个客户端,访问同一个数据库中的表来做例子。

串行化将所有的事务进行串行化。事务按照到来的顺序进行排队。多个事务并发过程中,对数据的变更需要按照顺序来做,不能同时做,也就是说,几个mysql语句会放入到一个等待队列,当前语句加锁,完成语句后,再从队列中拿出下一个语句去执行。

7、总结

隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。

不可重复读的重点是修改和删除:同样的条件,你读取过的数据,再次读取出来发现值不一样了。

幻读的重点在于新增:同样的条件,第1次和第2次读出来的记录数不一。一般情况下mysql默认的RR级别尽量不要改。

事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大。

4、事务一致性

MySQL对于一致性并没有做什么,一致性是和事务相关的。

事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。

一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的。

在技术层面上,MySQL实现了原子性、持久性、隔离性,通过这三个保证了一致性,即AID保证C。数据库提供技术,而真正的实现由用它的人来共同维护。

5、事务隔离性

数据库并发的场景有3种,读读并发,读写并发,写写并发。读读不需要并发控制。读写并发是主要的问题。

读写并发采用的是多版本并发控制(MVCC)的无锁并发机制来就解决读写冲突。

MySQL为每个事务分配一个单向增长的事务ID,ID越小,事务来得越早。mysqld对于事务的管理是先描述再组织,也就是要么是一个结构体要么是一个类,因为mysqld是用C++写的,另外事务也有自己的结构体。

1、隐藏字段

建表时,有一些字段是默认加上去的。

DB_TRX_ID:6 byte,最近修改( 修改/插入 )事务ID,记录创建这条记录/最后一次修改该记录的事务ID。初始为null。

DB_ROLL_PTR:7 byte,回滚指针,指向这条记录的上一个版本(简单理解成,指向历史版本就行,这些数据一般在 undo log 中)。在改数据前,先保存一份,这样就可以回滚了。默认为1。

DB_ROW_ID:6 byte,隐含的自增ID(隐藏主键),如果数据表没有主键, InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引。这个ID是隐藏的,对应着隐藏的主键,需要用这个隐藏的主键才能用到这个隐藏的索引,所以当我们没有设置主键时,是不会动用这个隐藏索引的。默认为null。

另外有一个字段是flag,用来表示删除的状态,更新或者删除不是真的删除,而是flag变了。

2、undo日志

mysql服务启动时会有自己的一个内存缓冲区,其中有一块空间是undo log。所以undo log就是mysql维护的一块内存缓冲区,以守护进程的形式运行,用来保存日志数据。

3、模拟MVCC

假设有个事务7,要把stu表中记录进行修改,name张三改成name李四。

因为事务7要修改,所以对表的记录先加锁保护;将要修改的记录拷贝到undo log中,此时原记录中回滚指针里存的就是undo log中本记录存储的地址;在原表中修改,修改后事务ID更新为7;最后提交,释放锁。

下一个事务开始运行时,也是一样的步骤,回滚指针需要更新,事务ID需要更新。undo log里不断添加拷贝过来的记录,记录之间可通过回滚指针来访问到,这就构成了一个版本链。

回滚时就是通过回滚指针,拿到undo log中对应的记录,覆盖一下即可。如果是insert记录,那么放到undo log中的记录可以变成相反的记录,delete,这样回滚时就能返回之前的记录了。对于不同的操作,mysql的回滚有对应的操作。

undo log中的一个个记录,就是一个个版本,也叫快照,多版本就是MVCC机制。当一个事务提交后,和这个事务相关的快照全都释放。

update和delete有版本链,insert并没有版本,但它要插入的数据也会存在undo log里,存的形式是delete,所以回滚的时候就是在删除之前插入的数据。

对于当前版本的update,delete,select都叫当前读,select可以当前读,也可以快照读,也就是读历史版本。隔离级别决定了select如何读。如果删改都是当前读,select是快照读,那么它们之间就不受加锁限制,效率更高;如果三者都是当前读,那么就得串行化执行。所以MySQL默认是可重复读级别。

事务之间有顺序,并发执行,所以各种操作必然有交错,这就是隔离性和隔离级别要解决的问题。

4、Read View

Read View是事务在快照读时生成的读视图。读视图本质是一个类,用来做可见性判断。当某个事务进行快照读时,对该记录创建一个读视图,用读视图中的字段来判断能看到哪些版本的数据。

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;
/** 标记视图是否被关闭*/
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

在这里插入图片描述

源码
在这里插入图片描述

读视图是事务可见性的一个类,不是事务创建出来时就有读视图,而是当事务已经存在并首次进行快照读时,mysql才形成读视图。

例子

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

6、读提交RC、可重复读RR的区别

RR级别下,两个事务同时进行,第二个事务开启后先select一下表;第一个事务更改,另一个再select就看不到了,这时可以写select * from 表名 lock in share mode让这个事务做当前读。如果第二个事务等到第一个事务更改完并提交后再第一次select那么就可以看到了,不需要多谢lock…。第一种情况读视图形成时,读视图认为两个事务都在运行,所以不能看到;第二种情况读视图形成前第一个事务就结束了,所以此时对于读视图来说,第一个事务是之前的事务,可以查看。

所以开始快照读的时机很重要,这个影响了快照读的能力。

在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才会有不可重复读问题。

结束。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于游戏开发的那些工具

大家好我是咕噜美乐蒂,很高兴又和大家见面了!下面我就和大家一起来了解一下有关游戏开发需要哪些工具呢。 游戏开发是一个涉及多个领域和环节的复杂过程,需要使用各种工具来辅助开发人员完成各项任务。下面将介绍一些常用的游戏开发工具&…

强化学习(TD3)

TD3——Twin Delayed Deep Deterministic policy gradient 双延迟深度确定性策略梯度 TD3是DDPG的一个优化版本,旨在解决DDPG算法的高估问题 优化点: ①双重收集:采取两套critic收集,计算两者中较小的值,从而克制收…

第一个 Angular 项目 - 动态页面

第一个 Angular 项目 - 动态页面 使用的所有技巧都在下面的笔记里: [Angular 基础] - 数据绑定(databinding) [Angular 基础] - 指令(directives) 以上为静态页面,即不涉及到跨组件交流的内容 以下涉及到组件内的沟通,从这开始数据就“活”…

Leetcode 3040. Maximum Number of Operations With the Same Score II

Leetcode 3040. Maximum Number of Operations With the Same Score II 1. 解题思路2. 代码实现 题目链接:3040. Maximum Number of Operations With the Same Score II 1. 解题思路 这一题的话思路就是一个动态规划,显然对于每一种情况都有3种可能的…

才气系统与逻辑系统道装实现的比较

才气系统与逻辑系统道装实现的比较 道装道装思想简介烛火流形学习引擎,流形学习的引入王船山信息熵,简称王船山熵;凝聚态数学可计算函数科学方法道装由来琴语言简介逻辑与才气的逐层比较表格(王船山熵) 道装 道装思想…

OpenCV 入门讲解

OpenCV 入门讲解 OpenCV(Open Source Computer Vision Library) 是一个开源的计算机视觉库,它提供了许多高效实现计算机视觉算法的函数,从基本的滤波到高级的物体检测都有涵盖。OpenCV 使用 C/C 开发,同时也提供了 Pyt…

短链接系统测试报告

目录 项目背景 项目功能 自动化测试 总结 项目背景 随着互联网的发展,链接(URL)变得越来越长且复杂,这不仅影响用户体验,还可能由于字符限制导致在某些平台或应用中无法完整显示。为了解决这一问题,我…

Ubuntu22.04LTS编译Frida历史版本,环境配制及细节调整

经常使用Frida的朋友们可能会遇到Frida的各种问题需要自定义的,而这时候Frida的本地编译就显得很重要了。 最近一位朋友发现使用Frida14/15/16版的server只能连拉一定数量的设备,超过了frida-device-manager便不能连接设备。 实现没有办法,…

综合练习

目录 查询每个员工的编号、姓名、职位、基本工资、部门名称、部门位置 确定要使用的数据表 确定已知的关联字段 查询每个员工的编号、姓名、职位、基本工资、工资等级 确定要使用的数据表 确定已知的关联字段 查询每个员工的编号、姓名、职位、基本工资、部门名称、工资…

⭐北邮复试刷题589. N 叉树的前序遍历__DFS (力扣每日一题)

589. N 叉树的前序遍历 给定一个 n 叉树的根节点 root ,返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。 示例 1: 输入:root [1,null,…

数据结构与算法:二叉树

一、二叉树的链式存储 树结点数据结构 typedef char BiElemType; typedef struct BiTNode{BiElemType c;struct BiTNode *lchild;struct BiTNode *rchild; }BiTNode,*BiTree;树中任何一个结点都是一个结构体,它的空间是通过malloc申请出来的 二、二叉树层次建树 …

<网络安全>《38 网络攻防专业课<第四课 - windows常见漏洞>》

1 系统漏洞概述 系统漏洞概述: 漏洞是指应用软件或操作系统软件在逻辑设计上的缺陷,或在编写时产生的错误。 漏洞是硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。 2 Window…

JS面向对象:六.原型链

原型链是 JavaScript 中实现对象之间继承关系的一种机制。在 JavaScript 中,每个对象都有一个指向另一个对象的链接,这个链接被称为原型。当试图访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 就会沿着…

数据安全之认识数据资产管理平台

文章目录 一、什么是数据资产二、什么是数据资产管理平台1、什么是数据资产管理平台2、为什么需要数据资产管理平台 三、数据资产管理平台的主要功能四、数据资产管理平台的工作原理五、数据资产管理平台的应用场景六、安全资产管理平台与数据资产管理平台的区别与关系1、安全资…

华为配置旁挂二层组网直接转发示例

配置旁挂二层组网直接转发示例 组网图形 图1 配置旁挂二层组网直接转发示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件扩展阅读 业务需求 企业用户通过WLAN接入网络,以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff…

已解决ModuleNotFoundError: No module named ‘cv2’异常的正确解决方法,亲测有效!!!

已解决ModuleNotFoundError: No module named ‘cv2’异常的正确解决方法,亲测有效!!! 文章目录 问题分析 报错原因 解决思路 解决方法 总结 在处理图像和视频等计算机视觉任务时,OpenCV是一个非常强大的库。然而…

数据库:存储、管理和分析数据的基石——数据库的介绍,分类,作用和特点

引言: 在现代信息时代,数据的管理和存储成为各个领域中不可或缺的一部分。数据库技术应运而生,它提供了一种结构化方式来组织、存储和管理数据。本文将详细介绍数据库的概念,并对常见的数据库进行分类,探讨它们的作用、…

图像处理之《隐写网络的隐写术》论文阅读

一、文章摘要 隐写术是一种在双方之间进行秘密通信的技术。随着深度神经网络(DNN)的快速发展,近年来越来越多的隐写网络被提出,并显示出良好的性能。与传统的手工隐写工具不同,隐写网络的规模相对较大。如何在公共信道上秘密传输隐写网络引起…

Linux colrm命令教程:如何移除文本文件中的指定列(附实例详解和注意事项)

Linux colrm命令介绍 colrm(column remove)命令在Linux中用于编辑源代码文件、脚本文件或常规文本文件中的文本。此命令可以从文件中移除选定的列。在这里,列被定义为一行中的单个字符。它始终从索引1开始,而不是0。 Linux colr…

anomalib1.0学习纪实-续2:三个文件夹

为了读懂程序,有三个最重要的文件夹,如下图: 正好对应四个类,如下图: 三个类的来源如下图所示: 注意,MVTec是个大类,里面用到了这里的第四个类MVTecDataset,代码如下。…