MySQL学习记录——십이 事务

news2024/12/30 3:22:48

文章目录

  • 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.coloradmin.cn/o/1457441.html

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

相关文章

【C语言必刷题】3.二分查找

📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有…

成功靠运气还是能力?我写了一个运气模拟器,告诉给你答案

前端训练营:1v1私教,终身辅导计划,帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ 视频版可直接访问:https://www.bilibili.com/video/BV1ct421b7Q7/?vd_source391a8dc379e0da60c77490e3221f097a…

oauthlib,一个强大的 Python 身份校验库!

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 目录 ​编辑 前言 什么是 OAuthLib? 安装 OAuthLib OAuthLib 的主要功能 OAuthLib 的用法 实现…

自己动手写编译器:使用 PDA 实现增强和属性语法的解析

在前面章节中我们了解了增强语法和属性语法,特别是看到了这两种语法的结合体,本节我们看看如何使用前面我们说过的自顶向下自动机来实现这两种语法结合体的解析,这里使用的方法也是成熟编译器常用的一种语法解析算法。 首先我们先给出上一节…

区块链金融科技:技术融合与挑战应对【文末送书-16】

文章目录 前言一.区块链与金融科技的融合:革新金融格局的技术之光1.1区块链技术简介1.2 区块链在金融科技中的应用 二.智能合约2.1 去中心化金融(DeFi)2.2区块链对金融科技的影响2.3数据安全性 三.区块链与金融科技【文末送书-16】3.1 粉丝福…

如何训练Ai把古诗《如梦令》描写的意境画出来?

常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。 古诗《如梦令》以其优美的语言和丰富的意境给人留下深刻的印象。今天,我们将借助AI的力量,将这首诗的意境转化为视觉画面…

x86使用页表实现虚拟内存原理分析---使用代码分析

分页机制 这一部分在手册第四章 视频讲解可以看这一个课程 在不使用分页机制的时候, 我们看到的是物理内存, 物理内存有多大, 我们就可以使用多大的内存 使用内存分页机制, 我们就可以扩充访问的地址范围, 也可以实现权限的细分, 实际上就是实现虚拟内存, 将地址进行映射, 看到…

希尔排序算法

目录 ShellSort希尔排序 整体思路 图解分析 【1】预排序 单组排序 多组并排 【2】直接插入排序 关于gap取值 总代码实现 时间复杂度 ShellSort希尔排序 希尔排序法又称缩小增量法。 希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有…

产品经理学习-产品运营《流程管理》

如何进行流程管理 信息可视化 甘特图-流程管理思维导图-方案讨论原型图-活动文档 明确责任制 分工明确,关键环境有主负责人通过时间倒推督促管理 沟通技巧 明确共同利益以结果激励做好信息同步 如何进行监控活动效果 监控活动的效果是要监控数据 活动每个环境的…

MySQL学习记录——십일 索引

文章目录 1、了解索引2、聚簇、非聚簇索引3、操作1、主键索引2、唯一键索引3、普通索引4、注意事项 4、全文索引 1、了解索引 MySQL服务器是在内存中的,所有数据库的CURD操作都是在内存中进行,索引也是如此。索引是用来提高性能的,它通过组织…

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明、API参考手册入口

目录 一、RT-Thread主要功能组件 二、内核组件 2.1 概述 2.2 API 三、设备驱动 3.1 概述 3.2 API 四、通信组件 4.1 概述 4.4 API 五、网络组件 5.1 概述 5.2 API 5.3 补充:MQTT协议 六、文件系统 6.1 概述 6.2 API 七、GUI 组件 7.1 概述 7.2 …

进程终止与进程等待

fork 函数 fork 函数是 Linux 中一个非常重要的函数&#xff0c;它的作用是从已存在的进程中创建一个新进程。这个新进程就是当前进程的子进程。 fork() 函数使用方法&#xff1a;它在头文件 #include <unistd.h> 中&#xff0c;函数原型为 pid_t fork(void); 用一个…

CMNet:Contrastive Magnification Network for Micro-Expression Recognition 阅读笔记

AAAI 2023的一篇文章&#xff0c;东南大学几位老师的工作&#xff0c;用于做微表情识别中的运动增强工作&#xff0c; 以下是阅读时记录的笔记。 摘要&#xff1a; However,existing magnification strategies tend to use the features offacial images that include not onl…

Minio通过Url直接访问附件

1、修改桶策略为public 2、http://locahost:9000/桶名/文件名即可 访问该文件&#xff0c;自己浏览 http://127.0.0.1:9000/netcore/netcore/9d4a526b-a477-46a3-90c7-a668354e3b46.png

C语言每日一题(59)左叶子之和

题目链接 力扣网404 左叶子之和 题目描述 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 2…

【C++航海王:追寻罗杰的编程之路】vector

目录 1 -> vector的介绍及使用 1.1 -> vector的介绍 1.2 -> vector的使用 1.2.1 -> vector的介绍 1.2.2 -> vector iterator的使用 1.2.3 -> vector空间增长问题 1.2.4 -> vector的增删查改 1.2.5 -> vector迭代器失效问题 2 -> vector的深…

K8s进阶之路-控制器无状态服务:

RC/RS/Deployment 控制器 deployment无状态&#xff08;最常用&#xff09;&#xff1a; nginx和Apache statefulset有状态&#xff1a; mysql和redis damonset初始化 job一次性任务 cronjob任务计划 1无状态&#xff1a;不会对本地环境产生依赖如&#xff1a;nginx和Apache …

Docker详解及使用

文章目录 为什么要用docker为什么会出现容器Docker 是什么容器是什么虚拟化是什么Docker 和 虚拟化的区别Docker 容器有几种在状态什么是仓库什么是镜像什么是容器仓库、镜像、容器的关系常用的 Docker 命令如何把主机的东西拷贝到容器内部如何让容器随着 Docker 服务启动而自动…

八、右侧下部页面内容区域

内容区可直接放置router-view占位子路由展示位置 所有内容区路由是layout的子路由&#xff0c;子路由需要在父路由中使用router-view占位才能显示app.vue是所有其他组件的父view/router&#xff0c;router里的父子关系通过来展现。所以在app.vue也要router-view标签 也可拆成组…

⭐北邮复试刷题LCR 012. 寻找数组的中心下标__前缀和思想 (力扣119经典题变种挑战)

LCR 012. 寻找数组的中心下标 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那么左侧数之和视为 0 &#xff0c;因为…