【MySQL实战45讲笔记】基础篇——事务隔离

news2024/11/23 23:57:01

系列文章

基础篇——MySQL 的基础架构
基础篇——redo log 和 binlog


目录

  • 系列文章
  • 1. 事务隔离
    • 1.1 隔离性与隔离级别
    • 1.2 如何实现事务隔离
    • 1.3 事务的启动方式
    • 1.4 思考: 使用什么方案来避免长事务


1. 事务隔离

简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的。但并不是所有的存储引擎都支持事务,比如MySQL 原生的 MyISAM 引擎就不支持事务(这也是 MyISAM 被 InnoDB 取代的重要原因之一)。

1.1 隔离性与隔离级别

事务的隔离性关注并发访问的数据可见性。

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

隔离级别越高,系统的效率就越低。因此很多时候,我们都要在二者之间寻找一个平衡点。SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。

我们通过下面这个例子来理解这四个隔离级别:

img

  • 若隔离级别是“读未提交”, 就是说A事务能够看到B事务未提交的值,所以则 V1 、V2、V3 都是 2。可能出现“脏读”
  • 若隔离级别是“读提交”,就是说则事务 B 的更新在提交后才能被 A 看到。所以, V1 是 1,V2 、 V3 的值是 2。避免了“脏读”,但不能避免""幻读和不可重复读取”
  • 若隔离级别是“可重复读”,那么要遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。因此A事务在提交前看到的数据都是一致的,所以, V1、V2 是 1,V3 是 2。避免了“脏读和不可重复读取“的情况,但不能避免“幻读”
  • 若隔离级别是“串行化”,是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。因此在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。串行化的隔离级别最高,能够避免脏读、不可重复读、幻读,但性能损耗也最大。

Oracle数据库默认隔离级别是“读提交”,MySQL的认隔离级别是“可重复读”。相关的配置参数是transaction-isolation

在这里插入图片描述

在实现上,数据库里面会创建一个视图,这里的视图是指数据库为了实现特定的隔离级别而创建的逻辑上的数据快照。这个视图决定了事务可以看到哪些数据版本。 在可重复读(REPEATABLE READ)这个隔离级别下,事务在开始时创建一个视图,整个事务期间都使用这个视图。这意味着事务在执行期间看到的数据是一致的,即使其他事务对这些数据做了修改并提交,当前事务也不会看到这些更改。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

1.2 如何实现事务隔离

上面介绍了事务的隔离级别,下面展开说明“可重复读”这一隔离级别是如何实现的。

在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。也就是说会有一个undo log记录回滚操作。

假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。

img

当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如图中看到的,在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到。(更具体的,务会根据自己的视图数组中的事务ID和版本号来判断所查询数据是否可见。如果查询时刻的事务启动时刻在数据版本提交之前,那么数据将不可见;如果在数据版本提交之后,数据将可见。)

对于回滚日志,肯定是不能一直保留的,当当系统里没有比这个回滚日志更早的 read-view 的时候,也就是没有事务再需要用到这些回滚日志时,回滚日志会被删除。

所以建议尽量不要使用长事务。因为长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。除此之外,长事务还占用锁资源,也可能拖垮整个库。

1.3 事务的启动方式

MySQL 的事务启动方式有以下几种:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  2. 隐式自动开启事务。set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了(正常来说select是不会启动事务,但是加了这个set命令后,此后的所有的sql语句的执行都会包含在该事务中。),而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。因此,建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。

在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务。如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

你可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

1.4 思考: 使用什么方案来避免长事务

从业务方角度:

  1. set autocommit参数值设置为1。测试环境中检查项目是否使用了set autocommit=0可以通过把 MySQL 的 general_log 开起来,然后随便跑一个业务逻辑,通过 general_log 的日志来确认。因为general_log 记录了所有执行的 SQL 语句,包括设置会话变量的语句(如 SET autocommit=0)。一般框架如果会设置这个值,也就会提供参数来控制行为,你的目标就是把它改成 1。(需要注意的是,开启 general_log 可能会对 MySQL 服务器的性能产生影响,因为它会记录所有的查询,所以建议只在测试环境中使用,并在确认问题后及时关闭。)

  2. 去掉没必要的只读事务。因为即使只读事务不修改数据,它们在开始时也可能获取共享锁,这会阻止其他事务(包括写事务)获取排他锁。如果只读事务持续时间很长,它们持有的共享锁就会阻塞其他事务的进行。并且在MySQL里,即使是只读事务,也可能占用回滚段资源。

  3. 业务连接数据库的时候,根据业务本身的预估,通过 SET MAX_EXECUTION_TIME 命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间(关于MAX_EXECUTION_TIME值设置为多少,通常建议的实践是先在测试环境中评估业务查询的平均执行时间,并根据这个评估来设置合理的MAX_EXECUTION_TIME值。同时,也要考虑到系统的负载情况和性能要求)。

从数据库角度:

  1. information_schema.Innodb_trx 表,设置长事务阈值,超过就报警 / 或者 kill;

  2. Percona 的 pt-kill 这个工具不错,推荐使用;

  3. 在业务功能测试阶段要求输出所有的 general_log,分析日志行为提前发现问题;

  4. 如果使用的是 MySQL 5.6 或者更新版本,把 innodb_undo_tablespaces 设置成 2(或更大的值)。innodb_undo_tablespaces是控制undo是否开启独立的表空间的参数 为0表示undo使用系统表空间,即回滚段保存在ibata文件中 ;不为0表示使用独立的表空间,一般名称为 undo001 undo002。

    这样如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。

    不过这个参数在MySQL8.0之后会被撤销,作为替代的是可以在运行时使用 CREATE UNDO TABLESPACE语法创建额外的撤消表空间(官方文档:[15.6.3.4 撤消表空间_MySQL 8.0 参考手册]):

    CREATE UNDO TABLESPACE tablespace_name ADD DATAFILE 'file_name.ibu';
    

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

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

相关文章

upload-labs-master第12关详细教程

成功了别忘了回来留下你的评论哦,嘻嘻 目录 环境配置闯关 环境配置 需要的东西 phpstudy-2018 链接: https://pan.baidu.com/s/1D9l13XTQw7o6A8CSJ2ff9Q 提取码:0278 32位 vc9和11运行库 链接: https://pan.baidu.com/s/1pBV3W…

Mac 修改默认jdk版本

当前会话生效 这里演示将 Java 17 版本降低到 Java 8 查看已安装的 Java 版本: 在终端(Terminal)中运行以下命令,查看已安装的 Java 版本列表 /usr/libexec/java_home -V设置默认 Java 版本: 找到 Java 8 的安装路…

uniapp奇怪bug汇总

H5端请求api文件夹接口报错 踩坑指数:5星 小程序、APP之前都是用api文件夹的接口引用调用,在h5端启动时报错,研究半天,发现把api文件夹名字改成apis就能调用,就像是关键字一样无法使用。 import authApi from /api/…

交换机配置从IP(Switch Configuration from IP)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

大语言模型---ReLU函数的计算过程及其函数介绍

文章目录 1. 概要2. ReLU定义 1. 概要 **ReLU 作用:**主要用于为神经网络引入非线性能力,作用是将输入中的整数保留原值,负数置为 0。 从而在层与层之间引入非线性,使神经网络能够拟合复杂的非线性关系。 **ReLU使用场景&#xf…

QT如何共享文件+拷贝文件

QString sharedFolderPathImg "\\\\" IP "/profileImage/"; // 更换为你的共享文件夹路径QDir dirImg(sharedFolderPathImg);dirImg.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);QVector<QString> curFileEntryArrayImg dirImg.entryList…

sourceTree无效的源路径问题解决

1.点击工具 2.点击选项 3.修改ssh客户端为OpenSSH 4.点击确定&#xff0c;然后重新打开软件

智慧营区整体解决方案

智慧军营概述智慧军营以信息化平台为基础&#xff0c;整合物联网、大数据、云计算、AI智能等技术&#xff0c;构建集人员、车辆、安防管理于一体的物联网平台。通过信息技术和网络技术&#xff0c;提高管理可控性&#xff0c;减少管理流程&#xff0c;降低成本&#xff0c;实现…

node实战:创建第一个简单的应用项目

1、确保node已安装 node -vnpm -v 2、创建项目文件夹 mkdir first-node-app-demo 3、初始化项目 3.1 执行&#xff08;输入&#xff09;命令 cd first-node-app-demo npm init -y 3.2 控制台输出 3.3 查看项目中的package.json文件 3.4 修改package.json文件 {"name…

STL——vector(1)

博客ID&#xff1a;LanFuRenC系列专栏&#xff1a;C语言重点部分 C语言注意点 C基础 Linux 数据结构 C注意点 今日好题 声明等级&#xff1a;黑色->蓝色->红色 欢迎新粉加入&#xff0c;会一直努力提供更优质的编程博客&#xff0c;希望大家三连支持一下啦 目录 尾…

pycharm在使用conda虚拟环境时Terminal爆红问题

问题&#xff1a; 解决方法&#xff1a; 复制cmd.exe后面所有路径 添加到pycharm的shell path中&#xff1a;

嵌入式LVGL自定义纯数字键盘

嵌入式LVGL自定义纯数字键盘 一、前言二、设置自定义数字键盘三、使用一、前言 嵌入式UI项目中有时候会使用到纯数字密码的需求,所以打算使用LVGL构建自定义的纯数字键盘。 二、设置自定义数字键盘 参考这个文章,以LV_KEYBOARD_MODE_USER_1为例,增加一个数字键盘,如下图所…

太速科技-512-基于ZU19EG的4路100G 8路40G的光纤汇流计算卡

基于ZU19EG的4路100G 8路40G的光纤汇流计算卡 一、板卡概述 本板卡系我司自主设计研发&#xff0c;基于Xilinx公司Zynq UltraScale MPSOC系列SOC XCZU19EG-FFVC1760架构&#xff0c;ARM端搭载一组64-bit DDR4&#xff0c;总容量达4GB&#xff0c;可稳定运行在2400MT/s…

【java-Neo4j 5开发入门篇】-最新Java开发Neo4j

系列文章目录 前言 上一篇文章讲解了Neo4j的基本使用&#xff0c;本篇文章对Java操作Neo4j进行入门级别的阐述&#xff0c;方便读者快速上手对Neo4j的开发。 一、开发环境与代码 1.docker 部署Neo4j #这里使用docker部署Neo4j,需要镜像加速的需要自行配置 docker run --name…

时间请求参数、响应

&#xff08;7&#xff09;时间请求参数 1.默认格式转换 控制器 RequestMapping("/commonDate") ResponseBody public String commonDate(Date date){System.out.println("默认格式时间参数 date > "date);return "{module : commonDate}"; }…

华为防火墙技术基本概念学习笔记

1.防火墙概述 1.1防火墙与交换机、路由器对比 路由器与交换机的本质是转发&#xff0c;防火墙的本质是控制。 防火墙与路由器、交换机是有区别的。路由器用来连接不同的网络&#xff0c;通过路由协议保证互联互通&#xff0c;确保将报文转发到目的地;交换机则通常用来组建局域…

基于深度学习CNN算法的花卉分类识别系统01--带数据集-pyqt5UI界面-全套源码

文章目录 基于深度学习算法的花卉分类识别系统一、项目摘要二、项目运行效果三、项目文件介绍四、项目环境配置1、项目环境库2、环境配置视频教程 五、项目系统架构六、项目构建流程1、数据集2、算法网络Mobilenet3、网络模型训练4、训练好的模型预测5、UI界面设计-pyqt56、项目…

Java的方法、基本和引用数据类型

个人的黑马程序员java笔记 目录 方法 例&#xff1a;方法定义和调用 方法的重载 对于byte, short, int, long类型 方法的内存 基本数据类型 引用数据类型 方法的值的传递的内存原理 方法 方法&#xff08;method&#xff09;是程序中最小的执行单元格式 方法定义&a…

分层架构 IM 系统之架构演进

在电商业务日活几百万的情况下&#xff0c;IM 系统采用分层架构方式&#xff0c;如下图。 分层架构的 IM 系统&#xff0c;整体上包含了【终端层】、【入口层】、【业务逻辑层】、【路由层】、【数据访问层】和【存储层】&#xff0c;我们在上篇文章&#xff08;分层架构 IM 系…

【Docker】Docker介绍|部署|简单使用|镜像操作|容器操作|自动构建镜像

文章目录 DockerDocker介绍Docker简介Docker的主要特点为什么要使用Docker&#xff1f;Docker核心概念&#xff08;1&#xff09;镜像&#xff08;Image&#xff09;&#xff08;2&#xff09;容器&#xff08;Container&#xff09;&#xff08;3&#xff09;仓库&#xff08;…