【Mysql】事务原理与优化最佳实践(四)

news2024/11/22 14:30:32

前言

我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增 删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。 这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事 务隔离机制、锁机制、MVCC多版本并发控制隔离机制、日志机制,用一整套机制来解决多 事务并发问题。

事务

一组操作要么全部成功,要么全部失败,目的是为了保证数据的最终一致性
在这里插入图片描述
如上图操作:A向B转账1000,实际上就是A减少1000,B增加1000,不存在A减少了,B没增加。B增加了,A没减少。

事务ACID特性

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

比如下单操作,下单订单后需要减少库存,他们应该是同时的,比如说我们下单成功了,库存减少失败了,此时下单功能所做的操作应该需要进行回滚。

  • 一致性(Consistency):使用事务的最终目的,由其他三个特性以及业务代码证券逻辑来实现。

还下单的操作,比如下面代码库存的减少可能因为我的代码的不严谨使用try-catch从而没法达到一致性。

public void createOrder(){
	    //创建订单
	   try{
		//减少库存
       }catch(Exception e){
       }
}
  • 隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰,隔离性由Mysql的各种锁以及MVCC机制来实现

这部分比较重要,单独说。

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

这个就比较好理解哈

事务隔离性

InnoDB引擎中,定义了四种隔离级别供我们使用,级别越高事务隔离性越好,但性能就越低,而隔离性是由Mysql的各种锁以及MVCC机制来实现的。

  • read uncommit(读未提交):脏读
  • read commit(读已提交):不可重复读
  • repeatable read(可重复读):幻读
  • serializable(串行):解决上面所以问题,包括脏写

在工作中,我们用的大多是repeatable read和read commit,一些大厂用的比较多的是read commit,一些软件公司用的比较多的是repeatable read,可能实际上我们根本不关注这些隔离级别,就是使用的默认的repeatable read

隔离级别脏读不可重复读幻读
读未提交可能可能可能
读已提交不可能可能可能
可重复读不可能不可能可能
可串行花不可能不可能不可能

数据库的事物隔离越严格,并发副作用越小,但付出的代价也就越大,因为事物隔离实质上就是使事物在一定程度上串行化进行,这显然与并发是矛盾的。
同时,不通的应用对读一致性的事物隔离程度的要求也是不同的,比如许多应用对不可重读欢读并不敏感,可能更关心数据库并发访问的能力。

查看当前数据库的事物隔离级别:

show variables like 'tx_isolation';

设置事物隔离级别:

set tx_isolation = 'REPEATABLES-READ';

Mysq默认的事物隔离级别是可重复读,用Spring开发程序时,如果不设置隔离级别默认用Mysql设置的隔离级别,如果Spring设置了就用已经设置的隔离级别,下面我们来看一下隔离级别的案例分析。

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

在这里插入图片描述
在客户端A的事务提交之前,打开另一个客户端B,更新表account:

在这里插入图片描述
这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据:
在这里插入图片描述
一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到 的数据其实就是脏数据:
在这里插入图片描述
在客户端A执行更新语句update account set balance = balance - 50 where id =1,lilei的balance没有变成350,居然是400,是不是很奇怪,数据不一致啊,如果你这么
想就太天真了,在应用程序中,我们会用400-50=350,并不知道其他会话回滚了,要想解 决这个问题可以采用读已提交的隔离级别

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

在这里插入图片描述
在客户端A的事务提交之前,打开另一个客户端B,更新表account:
在这里插入图片描述
这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题
在这里插入图片描述
客户端B的事务提交
在这里插入图片描述
客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题
在这里插入图片描述

  • 可重复读
    打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有 记录
set tx_isolation='repeatable‐read';

在这里插入图片描述
在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交
在这里插入图片描述
在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重 复读的问题
在这里插入图片描述
在客户端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 是当前读(当前版本)
在这里插入图片描述
重新打开客户端B,插入一条新数据后提交
在这里插入图片描述
在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读
在这里插入图片描述
验证幻读
在客户端A执行update account set balance=888 where id = 4;能更新成功,再次查询 能查到客户端B新增的数据
在这里插入图片描述

  • 串行化:打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值
set tx_isolation='serializable';

在这里插入图片描述
打开一个客户端B,并设置当前事务模式为serializable,更新相同的id为1的记录会被 阻塞等待,更新id为2的记录可以成功,说明在串行模式下innodb的查询也会被加上行锁, 如果查询的记录不存在会给这条不存在的记录加上锁(这种是间隙锁,后面会详细讲)。 如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间 范围都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读。 这种隔离级别并发性极低,开发中很少会用

在这里插入图片描述

事务问题定位

1 #查询执行时间超过1秒的事务,详细的定位问题方法后面讲完锁课程后会一起讲解 
2 SELECT  *  FROM  information_schema.innodb_trx  WHERE  TIME_TO_SEC( timediff( now( ), trx_started ) ) > 1; 
 #强制结束事务 10 kill 事务对应的线程id(就是上面语句查出结果里的trx_mysql_thread_id字段的值)

大事务的影响

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

事务优化

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

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

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

相关文章

【C】函数

目录 【1】函数是什么 【2】C语言中函数的分类 【2.1】库函数 【2.2】如何学会使用库函数 【2.3】自定义函数 【3】函数的参数 【3.1】实际参数(实参) 【3.2】形式参数(形参) 【4】函数的调用 【4.1】传值调用 【4.2】传址调用 【…

kubernetes环境搭建及部署

一、kubernetes 概述 1、kubernetes 基本介绍 kubernetes,简称 K8s,是用 8 代替 8 个字符“ubernete”而成的缩写。是一个开源 的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的 应用简单并且高效…

【Python】文件

文章目录 一. 什么是文件二. 文件路径三. 打开文件四. 关闭文件五. 写文件1. 清空写2. 追加写 六. 读文件1. 使用 read 方法读取2. 使用 for 循环按行读取3. 使用 readlines 方法读取整个文件的内容 七. 上下文管理器1. 什么是上下文管理器?2. 为什么要有上下文管理…

ESP8266模块MQTT AT Commands 发送 json字符串

ESP8266 wifi模块介绍 ESP8266EX 由乐鑫公司开发,提供了⼀套⾼度集成的 Wi-Fi SoC 解决⽅案,其低功耗、紧凑设计和⾼稳定性可以满⾜⽤户的需求。ESP8266EX 拥有完整的且⾃成体系的 Wi-Fi ⽹络功能,既能够独⽴应⽤,也可以作为从机…

ORA-31664: unable to construct unique job name when defaulted

某个环境备份不足空间问题处理后,手动执行expdp备份的脚本,报错如下 Export: Release 11.2.0.4.0 - Production on Tue Jul 4 11:46:14 2023 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle D…

【海量数据挖掘/数据分析】之 决策树模型(决策树模型、决策树构成、决策树常用算法、决策树性能要求、信息增益、信息增益计算公式、决策树信息增益计算实例)

【海量数据挖掘/数据分析】之 决策树模型(决策树模型、决策树构成、决策树常用算法、决策树性能要求、信息增益、信息增益计算公式、决策树信息增益计算实例) 目录 【海量数据挖掘/数据分析】之 决策树模型(决策树模型、决策树构成、决策树常…

Windows环境部署MySQL_5.7的安装、测试连接以及卸载全过程实操手册

前言: 前面记录了双环境的oracle的安装卸载及相关测试评估,这里记录下 MySQL5.7社区免费版的部署手册。 什么是 MySQL MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于Oracle 公司。MySQL 是一种关系型数…

window.open()实现PDF预览

效果图如下: 页面使用: window.open(strUrl) 参数说明如下图:

深度学习笔记之Transformer(四)铺垫:LayerNormalization

深度学习笔记之Transformer——LayerNormalization 引言回顾:批标准化问题描述问题处理 层标准化批标准化无法处理的问题 引言 在介绍 Transformer \text{Transformer} Transformer模型架构之前,首先介绍 Transformer \text{Transformer} Transformer的…

linux 环境下ElasticSearch 7.1.6.3、kibana-7.16.3安装

安装包放入百度网盘,自取 链接:https://pan.baidu.com/s/1Uh9pKFoaz9qi4CE4_GmlOA?pwdroky 提取码:roky 快速演示下安装操作: ElasticSearch 7.1.6.3: 1.上传至服务器相应目录下 我传到的/home目录下&#xff0…

0、技术选型

技术选型参考: 系统数据流程图 框架发行版本选型 1)如何选择Apache/CDH/HDP版本? (1)Apache:运维麻烦,组件间兼容性需要自己调研。(一般大厂使用,技术实力雄厚&#xf…

【随笔】jupyter notebook启动打开文件出现:500 : Internal Server Error

错误: 看log有 module ‘mistune’ has no attribute BlockGrammar’错误 打开文件有500 : Internal Server Error 解决方法: pip install --upgrade jupyterhub pip install --upgrade --user nbconvertconda环境可以: conda install nbc…

使用Python开发ChatGPT AI工具助手(ChatCatsy):4天快速开发指南

引言: ChatGPT是一种基于人工智能的对话生成模型,它可以用于开发聊天机器人、虚拟助手等应用。本教程将指导您在3天内使用Python开发一个ChatGPT AI工具助手。无需担心,即使您是初学者,也可以轻松跟随本指南完成项目。 第一天&a…

Java-数据结构(三)-List:ArrayList和LinkedList及其相关面试题

目录 一、引言二、ArrayList2.1 ArrayList是什么?2.2 ArrayList的历史由来2.3 ArrayList的使用好处2.4 ArrayList的底层原理2.5 ArrayList的操作方法及代码示例 三、LinkedList3.1 LinkedList是什么?3.2 LinkedList的历史由来3.3 LinkedList的使用好处3.…

攻防世界_web

robots 题目描述是这样的,虽然这是一道基础题,但我确实还没有了解过robots协议 第一次知道是被御剑给扫描出来的后台文件 这次直接访问看看 初级题就是初级题,访问后得到提示,如果没做过我估计还不知道该咋整,这也是一…

Squid 缓存代理(一)---原理及搭建(传统代理、透明代理)

前言 Squid 是 Linux 系 统 中 最 常 用 的 一 款 开 源 代 理 服 务 软 件 ( 官 方 网 站 为 http://www.squid-cache.org),可以很好地实现 HTTP 和 FTP,以及 DNS 查询、SSL 等应用的缓存代理。缓存代理作为应用层的代理服务软件…

C#(四十八)之StreamWriter StreamWriter使用方法及与FileStream类的区别

StreamReader类的属性: CurrentEncoding:获取流使用的字符编码 EndOfStream:指示当前位置是否在流的末尾 StreamReader类的方法: Read():读取流中的下一个字符或下一组字符。 ReadBlock():读取一个字符…

使用Maven对Scala独立应用程序进行编

任务描述 本关任务:使用Scala编写一个找出README.md文件中包含a的行数和包含b的行数的程序,并使用Maven对程序进行编译打包提交到Saprk上。 相关知识 在终端中执行如下命令创建一个文件夹 sparkapp3作为应用程序根目录: cd ~ # 进入用户主…

银河麒麟服务器v10 sp1 redis开机自动启动

接上一篇:银河麒麟服务器v10 sp1 安装 redis_csdn_aspnet的博客-CSDN博客 将redis_init_script文件复制到/etc/init.d下,重命名为redisd: rootxxx-pc:cp /usr/local/redis/redis-7.0.11/utils/redis_init_script /etc/init.d/redisd 内容如…

可视化网页设计工具 Blocs「Mac」

Blocs是一款用于网页设计和开发的可视化工具。它提供了一个直观且强大的界面,使用户可以轻松地创建精美的网页,而无需编写代码。 使用Blocs,您可以通过拖放元素、调整布局、编辑文本和图像等来构建网页。它提供了丰富的预设组件和模板&#x…