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的租车管理平台/汽车租赁网站

功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括:首页、详情页、用户中心、家政入驻模块。后台功能包括:总览、车辆管理、分类管理…

第7集《佛遗教经》

和尚尼慈悲,诸位法师、诸位居士,阿弥陀佛! 请大家打开讲义第十三面,丙三、对治灭烦恼法要 基本上,从事宗教的修学,目的是为了改造我们的生命,希望透过宗教的修学,使生命离开痛苦&a…

【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的官网直…

Node响应Vue axios请求方法说明

1、安装 npm install axios import axios from "axios"; 2、Vue前端 get请求使用 axios.get(url, { params: { key:value } }) 来请求 post请求使用 axios.post(url, { key: value }) 来请求 3、Node后端 get请求使用 req.query[params_name] 来获取 post请求使…

若依不分离版本部署流程

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

Android widget基础指南

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

C 练习实例71-结构体

题目&#xff1a;编写input()和output()函数输入&#xff0c;输出5个学生的数据记录。 代码&#xff1a; #include <stdio.h> typedef struct{char name[20];char sex[2];int age; }student; //定义了一种新的数据类型&#xff0c;叫做&#xff1a;student void input(…

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

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

图形渲染基础学习

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

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

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

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

5.Langchain和InternLM搭建知识库 5.1环境 还是一样&#xff0c;开发机中创建镜像&#xff0c;以及所需依赖 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模…

python之GIL

GIL&#xff08;global interpreter lock&#xff09;&#xff0c;即全局解释器锁 在单核时代&#xff0c;崇尚优美、清晰、简单的 Python 之父选择在解释器层面实现了一把全局互斥锁&#xff0c;来保护 Python 对象从而实现对单核 CPU 的使用率&#xff0c;这种做法在单核时代…

git操作(二)

之前我们对于git已经有了一定的了解&#xff0c;现在我们学习一些关于git的新内容。 一.修改⽂件 首先&#xff0c;我们先来认识一个命令&#xff1a; git status //⽤于查看在你上次提交之后是否有对⽂件进⾏再次修改,注意指的是仓库和工作区对比 关于三区的内容&#xff…

如何有效利用API接口进行数据采集

在当今数字化的世界中&#xff0c;API&#xff08;应用程序编程接口&#xff09;作为数据交换的桥梁&#xff0c;对于电商企业来说尤为重要。它们允许企业从丰富的数据源中提取必要的信息&#xff0c;为商业决策提供数据支持。本文将围绕如何高效地利用API进行数据采集展开讨论…

实际生产中的一次非典型的基于jmeter的接口自动化实践

实际工作中遇到过一次自动化巡检的需求&#xff0c;作为测试人员没法从源代码入手&#xff0c;加之数据库也不熟悉&#xff0c;故采取接口自动化的方式来实现巡检&#xff0c;算是一种歪门邪道吧&#xff0c;应该不是接口自动化的常规使用方式。jmeter在这里的作用实际上也只是…

docker安装一系列镜像

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

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

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

C++递归复习3

输出n~1的整数 #include<bits/stdc.h> using namespace std; int n; void f(int); int main() {cin>>n;f(n);return 0; } void f(int n){if(n0) return;cout<<n<<endl;f(n-1); }求10097......41的值 #include<bits/stdc.h> using namespace st…