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

news/2024/12/22 19:09:30/

前言

我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增 删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。 这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事 务隔离机制、锁机制、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.ppmy.cn/news/732638.html

相关文章

布尔巴基学派-一个对现代数学有着极大影响的数学家的集体

简介 起源 20世纪30年代后期,法国数学期刊上发表了若干数学论文,所论问题深刻,内容详尽,署名为。1939年出版了一本《》这是一套关于现代数学的综合性丛书的第一卷,作者也是尼古拉布尔巴基。这逐渐引起人们的重视&…

机器学习项目中遇到的难题_现代难题:何时使用规则与机器学习

机器学习项目中遇到的难题 Machine learning is taking the world by storm, and many companies that use rules engines for making business decisions are starting to leverage it. However, the two technologies are geared towards different problems. Rules engines …

密码学简史(二)--- 区块链中的现代密码学

文章目录 5. 对称钥匙:DES加密法6. 非对称钥匙:RSA加密法6.1 不可逆模运算 --- DH密钥交换6.2 RSA加密法6.3 数字签名6.4 比特币中的密码学6.5 区块链中的密码学 更多文章: 从计算机时代开始,字母作为操作的最小单位的概念就消失了…

Spring Boot:构建 Spring 应用程序的现代方式

原文地址:https://www.ibm.com/developerworks/community/blogs/3302cc3b-074e-44da-90b1-5055f1dc0d9c/entry/spring-boot?langzh 大家都喜欢 Spring Framework,对吧? 我们已习惯 Spring 提供的现成特性,比如依赖注入、事务管理…

C++11(及现代C++风格)和快速迭代式开发

过去的一年我在微软亚洲研究院做输入法,我们的产品叫“英库拼音输入法” (下载Beta版),如果你用过“英库词典”(现已更名为必应词典),应该知道“英库”这个名字(实际上我们的核心开发…

MAD,现代安卓开发技术:Android 领域开发方式的重大变革~

Android 诞生已久,其开发方式保持着高频更迭,相较于早期的开发方式已大不相同,尤其是近几年 Google 热切推崇的 MAD 开发技术。其实很多开发者已经有意或无意地正在使用这门技术,借着 2022 开年探讨技术趋势的契机,想要…

【转载】萌新也能懂的现代 JavaScript 开发

有时候入门没入好,学习起现代的 JavaScript 开发还是颇有难度的。生态系统太日新月异以至于让人难以理解不同工具的出现究竟是为了解决什么问题。我从 1988 年开始编程,但直至 2014 年才开始认真地学习起 JavaScript。记得那时第一次遇到 Browserify 时看…

领先氢燃料电池技术助力未来出行 现代汽车惊艳进博会

2019年11月5日,第二届中国国际进口博览会在上海国家会展中心隆重开幕。作为中国坚定支持贸易自由化和经济全球化、主动向世界开放市场的重大举措,中国国际进口博览会的举办初衷,便是促进世界各国经贸交流合作和世界经济增长。 观众参观现代汽…