Mysql事务原理与优化

概述

我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。

这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事务隔离机制、锁机制、MVCC多版本并发控制隔离机制、日志机制,用一整套机制来解决多事务并发问题。接下来的,我们会深入讲解这些机制,让大家彻底理解数据库内部的执行原理。

事务及其ACID属性

事务是一组操作要么全部成功,要么全部失败,目的是为了保证数据最终的一致性。

事务具有以下4个属性,通常简称为事务的ACID属性。

  原子性(Atomicity) :当前事务的操作要么同时成功,要么同时失败。原子性由 undo log日志来实现。

  一致性(Consistent) :使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现。

  隔离性(Isolation) :在事务并发执行时,他们内部的操作不能互相干扰。隔离性由MySQL的各种锁以及MVCC机制来实现。

  持久性(Durable) :一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。

并发事务处理带来的问题
更新丢失(Lost Update)或脏写
当两个或多个事务选择同一行数据修改,有可能发生更新丢失问题,即最后的更新覆盖
了由其他事务所做的更新。
脏读(Dirty Reads)
事务A读取到了事务B已经修改但尚未提交的数据
不可重读(Non-Repeatable Reads)
事务A内部的相同查询语句在不同时刻读出的结果不一致
幻读(Phantom Reads)
事务A读取到了事务B提交的新增数据

事务隔离级别

脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。

隔离级别                   藏读                         不可重复读              幻读

读未提交(Read
uncommitted)               可能                         可能                      可能
读已提交(Read
committed)                   不可能                      可能                    可能
可重复读
(Repeatableread)          不可能                   不可能                   可能
可串行化
(Serializable)                 不可能                   不可能                 不可能

数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。

同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。

查看当前数据库的事务隔离级别: show variables like 'tx_isolation';

设置事务隔离级别:set tx_isolation='REPEATABLE-READ';

Mysql默认的事务隔离级别是可重复读

事务隔离级别案例分析

1	CREATE TABLE `account` (
2	`id` int(11) NOT NULL AUTO_INCREMENT,
3	`name` varchar(255) DEFAULT NULL,
4	`balance` int(11) DEFAULT NULL,
5	PRIMARY KEY (`id`)
6	) ENGINE=InnoDB DEFAULT CHARSET=utf8;
7	INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lilei', '450');
8	INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('hanmei', '16000');
9	INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lucy', '2400');

1、读未提交:

(1)打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询表account的初始值:

set tx_isolation='read‐uncommitted';

(2)在客户端A的事务提交之前,打开另一个客户端B,更新表account:

 (3) 这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据:

(4)一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据:

(5)在客户端A执行更新语句update account set balance = balance - 50 where id

=1,lilei的balance没有变成350,居然是400,是不是很奇怪,数据不一致啊,如果你这么想就太天真了,在应用程序中,我们会用400-50=350,并不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离级别

 2、读已提交

(1)打开一个客户端A,并设置当前事务模式为read committed(未提交读),查询表account的所有记录:

set tx_isolation='read‐committed';

(2)在客户端A的事务提交之前,打开另一个客户端B,更新表account:

(3)这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题

 (4)客户端B的事务提交

(5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题

3、可重复读 

(1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录

set tx_isolation='repeatable‐read';

(2)在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交

 (3)在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题

(4)在客户端A,接着执行update account set balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤2中的350来算的,所以是 300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作是快照读(历史版本);insert、update和delete 是当前读(当前版本)。

(5) 重新打开客户端B,插入一条新数据后提交

 (6)在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读

(7)验证幻读

在客户端A执行update account set balance=888 where id = 4;能更新成功,再次查询能查到客户端B新增的数据

4、 串行化

(1)打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值:

set tx_isolation='serializable';

()

(2)打开一个客户端B,并设置当前事务模式为serializable,更新相同的id为1的记录会被阻塞等待,更新id为2的记录可以成功,说明在串行模式下innodb的查询也会被加上行锁,如果查询的记录不存在会给这条不存在的记录加上锁(这种是间隙锁,后面会详细讲)。

如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读。

这种隔离级别并发性极低,开发中很少会用。 

大事务的影响 

并发情况下,数据库连接池容易被撑爆锁定太多的数据,造成大量的阻塞和锁超时执行时间长,容易造成主从延迟回滚所需要的时间比较长 undo log膨胀容易导致死锁

事务优化

将查询等数据准备操作放到事务外事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久事务中避免一次性处理太多数据,可以拆分成多个事务分次处理更新等涉及加锁的操作尽可能放在事务靠后的位置能异步处理的尽量异步处理应用侧(业务代码)保证数据一致性,非事务执行

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

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

相关文章

华为配置旁挂二层组网隧道转发示例

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

【python学习篇1】python基本语法

目录 一、第一个python程序 二、基本语法,数据类型,字面量,循环语句等内容 2.1字面量 2.2注释 2.2.1单行注释 2.2.2多行注释 2.3变量 2.3.1认识变量 2.3.2查看数据类型 2.3.3数据类型转换 2.3.4字符串的三种定义方式 2.3.5字符串…

Flutter开发环境和打包流程

Flutter开发环境和打包流程 1.本地开发环境 1.1.安装flutter 官网安装flutter有2种方式,一种是下载flutter的sdk包,一种是VS Code直接安装,照着官网的安装flutter的流程走没有什么问题 1.2.安装Android Studio 去Android Studio的官网直…

若依不分离版本部署流程

一、分离与不分离的区别 参考博客:前后端分离与不分离的本质区别!_前后端分离本质-CSDN博客 概念适用场景前后端不分离前端页面看到的效果都是由后端控制,由后端渲染页面或重定向适合纯网页应用前后端分离后端仅返回前端所需的数据&#xf…

Android widget基础指南

widget的概念最早是由一名叫Rose的苹果工程师提出,后来经过多方面机缘巧合的发展下,便有了今天Android平台上的小组件widget,一般APP开发可能应用场景较少,最常见的莫过于天气APP的widget。但对于从事IOT或车载方向的同学&#xf…

WebRTC最新版报错解决:FileNotFoundError: LASTCHANGE.committime (二十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

图形渲染基础学习

原文链接:游戏开发入门(三)图形渲染_如果一个面只有三个像素进行渲染可以理解为是定点渲染吗?-CSDN博客 游戏开发入门(三)图形渲染笔记: 渲染一般分为离线渲染与实时渲染,游戏中我们用的都是…

【Linux取经路】文件系统之重定向的实现原理

文章目录 一、再来理解重定向1.1 输出重定向效果演示1.2 重定向的原理1.3 dup21.4 输入重定向效果演示1.5 输入重定向代码实现 二、再来理解标准输出和标准错误2.1 同时对标准输出和标准错误进行重定向2.2 将标准输出和标准错误重定向到同一个文件 三、再看一切皆文件四、结语 …

书生开源大模型训练营-第3讲笔记

5.Langchain和InternLM搭建知识库 5.1环境 还是一样,开发机中创建镜像,以及所需依赖 pip install modelscope1.9.5 pip install transformers4.35.2 pip install streamlit1.24.0 pip install sentencepiece0.1.99 pip install accelerate0.24.15.2模…

docker安装一系列镜像

启动docker systemctl start docker docker 启动已经停止的容器 docker start idOrName PS:idOrName为容器的id或者名称 1、安装mysql镜像 拉取mysql5.7的镜像 docker pull mysql:5.7 查看镜像 docker images 启动mysql #启动mysql docker run --name mysql…

云呐电网智能运维包含哪些?智能运维都有哪些框架

电网智能运维是一个复杂的系统,包括多种技术和方法,为提升电力系统的效率和稳定性。以下是你提出的问题的实际答案: 网络智能运维的核心技术与应用: 故障检测:根据实时监测和数据分析,对电网中的故障进行快速、准确的…

LabVIEW读取excel日期

LabVIEW读取excel日期 | Excel数据表格中有日期列和时间列,如下表所示: 通过LabVIEW直接读取Excel表格数据,读出的日期列和时间列数据与原始表格不一致,直接读出来的数据如下表所示: 日期、时间列数据异常 问题产生原因…

VBA:批量复制sheet内指定内容

VBA. 批量复制sheet内指定内容 背景:一个excel内有包含0-18序号的Sheet,需要将1-18的sheet内包含标准差的行复制到sheet”0“中。 方法: 从1-18遍历sheet,找到单元格值为”标准差“的行,然后(仅复制值&a…

Linux下多核CPU指定程序运行的核

设置程序在指定CPU核心运行 一、如何查看程序运行的CPU信息 1.1 查看当前系统CPU有几个核心 查看CPU核心数量:lscpu 1.2 查看程序的PID ps aux|grep cpu_test1.3 查看程序可运行的CPU taskset -c -p pid1.4 设置程序在指定核心上运行 1.4.1 通过运行时的参数设…

[工具探索]VSCode介绍和进阶使用

相比较GoLand、PhpStorm、PyCharm、WebStorm的重量级内存占用,从Windows系统来,各种卡死,换到MacOS倒不会卡死,但是内存占用太多,影响体验,决定换到VSCode。当然这个过程需要适应过渡期,旧伙计都…

电脑文件误删除如何恢复?2024最新三种恢复方法

我们在使用电脑的过程中,随着时间的不断推移,渐渐的我们会发现C盘内存空间不足了。这是因为我们很多文件都默认存储在C盘,所以导致C盘空间不足,电脑运行越来越慢。那么电脑哪些文件可以删除,电脑删除的东西怎么恢复&am…

There will be “7“ later: Interpretation of next-generation Wi-Fi technology

With the Wi-Fi Alliance announcing the launch of Wi-Fi 7-related certifications, we can also start talking about the new successor to Wi-Fi 6 three years after its launch. What is Wi-Fi 7? What benefits does it bring? These questions about Wi-Fi 7 will b…

Active Directory 的密码管理策略

员工使用的密码可以决定或破坏组织中的数据安全性,但是,知道员工通常不遵循良好的密码卫生习惯也就不足为奇了。从在本机工具(如 Windows Active Directory 组策略)中设置弱密码和通用密码到宽松的密码策略规则,有几个…

钉钉小程序 没有调用该接口的权限

钉钉小程序 没有调用该接口的权限 problem 钉钉官方自带免登陆小程序 后端接口报错 {"errcode":60011,"errmsg":"没有调用该接口的权限,接口权限申请参考:https://open.dingtalk.com/document/orgapp-server/add-api-permiss…

【C++】---static成员(附OJ题)

一、静态成员变量 1.概念: 声明为static的类成员称为类的静态成员,静态成员分为两种: (1)static修饰的成员变量:静态成员变量 (2)static修饰的成员函数:静态成员函数 …