32 - MySQL调优之事务:高并发场景下的数据库事务调优

数据库事务是数据库系统执行过程中的一个逻辑处理单元,保证一个数据库操作要么成功,要么失败。谈到他,就不得不提 ACID 属性了。数据库事务具有以下四个基本属性:原子性(Atomicity)、一致性(Consistent)、隔离性(Isolation)以及持久性(Durable)。正是这些特性,才保证了数据库事务的安全性。而在 MySQL 中,鉴于 MyISAM 存储引擎不支持事务,所以接下来的内容都是在 InnoDB 存储引擎的基础上进行讲解的。

我们知道,在 Java 并发编程中,可以多线程并发执行程序,然而并发虽然提高了程序的执行效率,却给程序带来了线程安全问题。事务跟多线程一样,为了提高数据库处理事务的吞吐量,数据库同样支持并发事务,而在并发运行中,同样也存在着安全性问题,例如,修改数据丢失,读取数据不一致等。

在数据库事务中,事务的隔离是解决并发事务问题的关键, 今天我们就重点了解下事务隔离的实现原理,以及如何优化事务隔离带来的性能问题。

1、并发事务带来的问题

我们可以通过以下几个例子来了解下并发事务带来的几个问题:

1.1、数据丢失

img

1.2、脏读

img

1.3、不可重复读

img

1.4、幻读

img

2、事务隔离解决并发问题

以上 4 个并发事务带来的问题,其中,数据丢失可以基于数据库中的悲观锁来避免发生,即在查询时通过在事务中使用 select xx for update 语句来实现一个排他锁,保证在该事务结束之前其他事务无法更新该数据。

当然,我们也可以基于乐观锁来避免,即将某一字段作为版本号,如果更新时的版本号跟之前的版本一致,则更新,否则更新失败。剩下 3 个问题,其实是数据库读一致性造成的,需要数据库提供一定的事务隔离机制来解决。

我们通过加锁的方式,可以实现不同的事务隔离机制。在了解事务隔离机制之前,我们不妨先来了解下 MySQL 都有哪些锁机制。

InnoDB 实现了两种类型的锁机制:共享锁(S)和排他锁(X)。共享锁允许一个事务读数据,不允许修改数据,如果其他事务要再对该行加锁,只能加共享锁;排他锁是修改数据时加的锁,可以读取和修改数据,一旦一个事务对该行数据加锁,其他事务将不能再对该数据加任务锁。

熟悉了以上 InnoDB 行锁的实现原理,我们就可以更清楚地理解下面的内容。

在操作数据的事务中,不同的锁机制会产生以下几种不同的事务隔离级别,不同的隔离级别分别可以解决并发事务产生的几个问题,对应如下:

未提交读(Read Uncommitted):在事务 A 读取数据时,事务 B 读取和修改数据加了共享锁。这种隔离级别,会导致脏读、不可重复读以及幻读。

已提交读(Read Committed):在事务 A 读取数据时增加了共享锁,一旦读取,立即释放锁,事务 B 读取修改数据时增加了行级排他锁,直到事务结束才释放锁。也就是说,事务 A 在读取数据时,事务 B 只能读取数据,不能修改。当事务 A 读取到数据后,事务 B 才能修改。这种隔离级别,可以避免脏读,但依然存在不可重复读以及幻读的问题。

可重复读(Repeatable Read):在事务 A 读取数据时增加了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增加了行级排他锁,直到事务结束才释放锁。也就是说,事务 A 在没有结束事务时,事务 B 只能读取数据,不能修改。当事务 A 结束事务,事务 B 才能修改。这种隔离级别,可以避免脏读、不可重复读,但依然存在幻读的问题。

可序列化(Serializable):在事务 A 读取数据时增加了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增加了表级排他锁,直到事务结束才释放锁。可序列化解决了脏读、不可重复读、幻读等问题,但隔离级别越来越高的同时,并发性会越来越低。

InnoDB 中的 RC 和 RR 隔离事务是基于多版本并发控制(MVVC)实现高性能事务。一旦数据被加上排他锁,其他事务将无法加入共享锁,且处于阻塞等待状态,如果一张表有大量的请求,这样的性能将是无法支持的。

MVVC 对普通的 Select 不加锁,如果读取的数据正在执行 Delete 或 Update 操作,这时读取操作不会等待排它锁的释放,而是直接利用 MVVC 读取该行的数据快照(数据快照是指在该行的之前版本的数据,而数据快照的版本是基于 undo 实现的,undo 是用来做事务回滚的,记录了回滚的不同版本的行记录)。MVVC 避免了对数据重复加锁的过程,大大提高了读操作的性能。

3、锁具体实现算法

我们知道,InnoDB 既实现了行锁,也实现了表锁。行锁是通过索引实现的,如果不通过索引条件检索数据,那么 InnoDB 将对表中所有的记录进行加锁,其实就是升级为表锁了。

行锁的具体实现算法有三种:record lock、gap lock 以及 next-key lock。record lock 是专门对索引项加锁;gap lock 是对索引项之间的间隙加锁;next-key lock 则是前面两种的组合,对索引项以其之间的间隙加锁。

只在可重复读或以上隔离级别下的特定操作才会取得 gap lock 或 next-key lock,在 Select 、Update 和 Delete 时,除了基于唯一索引的查询之外,其他索引查询时都会获取 gap lock 或 next-key lock,即锁住其扫描的范围。

4、优化高并发事务

通过以上讲解,相信你对事务、锁以及隔离级别已经有了一个透彻的了解了。清楚了问题,我们就可以聊聊高并发场景下的事务到底该如何调优了。

4.1、结合业务场景,使用低级别事务隔离

在高并发业务中,为了保证业务数据的一致性,操作数据库时往往会使用到不同级别的事务隔离。隔离级别越高,并发性能就越低。

那换到业务场景中,我们如何判断用哪种隔离级别更合适呢?我们可以通过两个简单的业务来说下其中的选择方法。

我们在修改用户最后登录时间的业务场景中,这里对查询用户的登录时间没有特别严格的准确性要求,而修改用户登录信息只有用户自己登录时才会修改,不存在一个事务提交的信息被覆盖的可能。所以我们允许该业务使用最低隔离级别。

而如果是账户中的余额或积分的消费,就存在多个客户端同时消费一个账户的情况,此时我们应该选择 RR 级别来保证一旦有一个客户端在对账户进行消费,其他客户端就不可能对该账户同时进行消费了。

4.2、避免行锁升级表锁

前面讲了,在 InnoDB 中,行锁是通过索引实现的,如果不通过索引条件检索数据,行锁将会升级到表锁。我们知道,表锁是会严重影响到整张表的操作性能的,所以我们应该避免他。

4.3、控制事务的大小,减少锁定的资源量和锁定时间长度

你是否遇到过以下 SQL 异常呢?在抢购系统的日志中,在活动区间,我们经常可以看到这种异常日志:

MySQLQueryInterruptedException: Query execution was interrupted

由于在抢购提交订单中开启了事务,在高并发时对一条记录进行更新的情况下,由于更新记录所在的事务还可能存在其他操作,导致一个事务比较长,当有大量请求进入时,就可能导致一些请求同时进入到事务中。

又因为锁的竞争是不公平的,当多个事务同时对一条记录进行更新时,极端情况下,一个更新操作进去排队系统后,可能会一直拿不到锁,最后因超时被系统打断踢出。

在用户购买商品时,首先我们需要查询库存余额,再新建一个订单,并扣除相应的库存。这一系列操作是处于同一个事务的。

以上业务若是在两种不同的执行顺序下,其结果都是一样的,但在事务性能方面却不一样:

img

这是因为,虽然这些操作在同一个事务,但锁的申请在不同时间,只有当其他操作都执行完,才会释放所有锁。因为扣除库存是更新操作,属于行锁,这将会影响到其他操作该数据的事务,所以我们应该尽量避免长时间地持有该锁,尽快释放该锁。

又因为先新建订单和先扣除库存都不会影响业务,所以我们可以将扣除库存操作放到最后,也就是使用执行顺序 1,以此尽量减小锁的持有时间。

5、总结

其实 MySQL 的并发事务调优和 Java 的多线程编程调优非常类似,都是可以通过减小锁粒度和减少锁的持有时间进行调优。在 MySQL 的并发事务调优中,我们尽量在可以使用低事务隔离级别的业务场景中,避免使用高事务隔离级别。

在功能业务开发时,开发人员往往会为了追求开发速度,习惯使用默认的参数设置来实现业务功能。例如,在 service 方法中,你可能习惯默认使用 transaction,很少再手动变更事务隔离级别。但要知道,transaction 默认是 RR 事务隔离级别,在某些业务场景下,可能并不合适。因此,我们还是要结合具体的业务场景,进行考虑。

6、思考题

以上我们主要了解了锁实现事务的隔离性,你知道 InnoDB 是如何实现原子性、一致性和持久性的吗?

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

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

相关文章

Windows全系列 本地密码暴力破解

首先 咱们要准备两个工具: 第一个是 pwdump-master 第二个是 saminside_softradar-com.exe这两个工具 我会一并上传 需要的同学 可以自取本文章操作思路是: 第一步 首先把我刚刚提到的两个软件 以某种手段放置于机器中 如果是真实机 就用U盘 拷贝到真实机…

基于Java SSM框架+Vue实现药品保健品购物网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现药品保健品购物网站演示 摘要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 ssm药源购物网站,主要的模块包括两个用户,管理员权限:用…

RK3568平台开发系列讲解(Linux系统篇)pinctrl api介绍及实验

🚀返回专栏总目录 文章目录 一、pinctrl函数介绍二、设备树案例三、驱动案例 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍pinctrl api及其使用案例 。 一、pinctrl函数介绍 ①获取设备对应的 pinctrl…

西南科技大学数字电子技术实验一(数字信号基本参数与逻辑门电路功能测试及FPGA 实现)FPGA部分

一、 实验目的 1、掌握基于 Verilog 语言的 diamond 工具设计全流程。 2、熟悉、应用 Verilog HDL 描述数字电路。 3、掌握 Verilog HDL 的组合和时序逻辑电路的设计方法。 4、掌握“小脚丫”开发板的使用方法。 二、 实验原理 与门逻辑表达式:Y=AB 原理仿真图: 2 输入…

智慧工厂人员定位系统源码,融合位置物联网、GIS可视化等技术,实现对人员、物资精确定位管理

智慧工厂人员定位系统源码,UWB高精度定位系统源码 随着中国经济发展进入新常态,在资源和环境约束不断强化的背景下,创新驱动传统制造向智能制造转型升级,越发成为企业生存发展的关键。智能工厂作为实现智能制造的重要载体&#xf…

OpenGL之Mesa3D编译for Ubuntu20.04(三十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

Elasticsearch启动失败问题汇总

版本elasticsearch-8.11.1,解压安装完后,修改安装目录下conf/jvm.options, 默认配置如下: -Xms4g -Xmx4g 默认的配置占用内存太多了,调小一些: -Xms256m -Xmx256m由于es和jdk是一个强依赖的关系&#xff0…

jQuery_05 事件的绑定(尝试)

jQuery可以给dom对象添加事件 在程序执行期间动态的处理事件 jQuery如何绑定事件呢? 1. $("选择器").事件名称(事件处理函数) $("选择器") : 选择0或者多个dom对象 给他们添加事件 事件名称:就是js中事件名称去掉on的部…

【JAVA】SpringBoot + mongodb 分页、排序、动态多条件查询及事务处理

【JAVA】SpringBoot mongodb 分页、排序、动态多条件查询及事务处理 1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mongodb ↓ -->&…

力扣刷题篇之递归

系列文章目录 目录 系列文章目录 前言 一、二叉树相关问题 二、回溯相关问题 三、动态规划相关问题 总结 前言 刷题按照&#xff1a;[力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 - 力扣&#xff08;LeetCode&#xff09;&#xff0c;如图&#xff0c;因为是讲…

A start job is running for Hold unt…s up (1d 18h 52min 25s / no limit) 如何去掉

在host串口里一直出现打印 A start job is running for Hold unt…s up (1d 18h 52min 25s / no limit) 这个是有一个进程一直在执行中&#xff0c;那么是什么呢&#xff1f;因为我的host通过SSH连接后就可以进入host shell界面了。那这个线程是什么程序导致的呢&#xff1f; …

小程序域名SSL证书的重要性

1. 数据安全 小程序中可能涉及用户的个人信息、支付信息等敏感数据&#xff0c;而未加密的通信容易受到中间人攻击。通过使用SSL证书&#xff0c;所有数据在传输过程中都会被加密&#xff0c;确保用户信息不被窃取或篡改。 2. 用户信任 浏览器和操作系统对使用SSL证书的网站…

索引出错问题。为什么建立了索引,也避免了索引失效问题,还是会出现查询不走索引的情况?

什么建立了索引&#xff0c;也避免了索引失效问题&#xff0c;还是会出现查询不走索引的情况&#xff1f; 其实这个问题在于CBO&#xff08;Cost-based Optimizer&#xff09;&#xff0c;优化器是很强大的&#xff01;他根据开销来决定是否要用索引以及用哪个索引&#xff01;…

Spring-SpringFramework特性以及IOC相关知识

SpringFramework五大模块 特性 IOC思想和DI IOC是容器&#xff0c;用于管理资源 IOC&#xff1a;Inversion of Control 反转控制 DI&#xff1a;Dependecy Injection 依赖注入 组件以预先定义好的方式接受来自容器的资源注入 IOC在Spring中的实现 spring提供两种方式&…

图书管理系统源码,图书管理系统开发,图书借阅系统源码四TuShuManager应用程序MVC视图View

Asp.net web应用程序MVC之View视图 .ASP.NET MVC页面也就是要说的视图基本被放在Views文件夹下&#xff1b; 2.利用APS.NET MVC模板生成框架&#xff0c;Views文件夹下的默认页面为.cshtml页面&#xff1b; 3.ASP.NET MVC默认页面为Razor格式的页面&#xff0c;因此默认页面为.…

NX二次开发UF_CURVE_ask_wrap_curves 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_wrap_curves Defined in: uf_curve.h int UF_CURVE_ask_wrap_curves(tag_t wrap_curve_object, int * num_output_curves, tag_t * * output_curves ) overview 概述 …

了解静态测试?

静态测试是一种软件测试方法&#xff0c;它主要通过分析软件或代码的静态属性来检查潜在的问题和缺陷&#xff0c;而无需实际执行程序。这种测试方法侧重于检查源代码和其他软件文档&#xff0c;以发现错误并提高软件质量。 为什么要做静态测试&#xff1f; 提前发现和修复错…

[操作系统]京东一面~进程相关汇总

1 进程、线程、协程的概念 进程&#xff1a; 静态程序的运行状态就叫进程。是资源分配的基本单位。 线程&#xff1a; 是进程的一个执行单元&#xff0c;是进程内的调度实体。是CPU调度的独立单位。线程也被称为轻量级进程。 协程&#xff1a; 是一种比线程更加轻量级的存在。…

vue3安装eslint和prettier,最简单的步骤

第1步&#xff1a; 安装eslint yarn add eslint -D 第2步&#xff1a; 在根文件夹中&#xff0c;创建.eslintrc.js文件 第3步&#xff1a; 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…

红米手机如何远程控制荣耀手机?

很多人都知道&#xff0c;华为体系有【畅联】&#xff0c;与华为手机或平板“畅连”通话时&#xff0c;可共享屏幕给对方&#xff0c;一边聊天一边演示&#xff0c;还可在屏幕上涂鸦帮助理解。同样&#xff0c;小米体系有【小米通话】&#xff0c;它的远程协助功能可以帮助朋友…