大事务带来的问题

说到大事务,首先我们要说一说什么是事务,有两句话可以简单地描述事务,首先事务是关系型数据库区分于

其他一切文件系统的重要特性之一,比如举个例子来说,举个例子来说,这个文件系统中,如果要保证文件的

一致性,而在我们修改一个文件后,系统突然奔溃了,这样文件恢复后很难保证文件的一致了,而数据库系统中呢,

由于使用了事务,所以通常在数据库服务器奔溃了以后,我们可以恢复数据库的数据,使其数据还是保证一致性,

另一个对事务的描述呢,事务是一组具有原子性的SQL语句,可以是一组简单的查询,也可以是有多个增删改查锁组成的

一组SQL语句的集合,但是这一组是具有原子性的,也就是说,事务中的SQL要么全部完成,要么全部失败,从以上的描述

我们就可以看出

事务是要求符合以下特性的,事务要符合原子性,一致性,隔离性,持久性,下面我们可以分别来看一下事务的四个特性

首先我们来看看事务的原子性,一个事务呢必须被视为一个不可分割的最小单元,整个事务中的所有操作呢,

要么全部成功,要么全部失败,对于一个事务来说,不可能只执行其中的一部分,这就是事务的原子性的定义,

在通常情况下,说到事务的原子性

在通常的情况下说到事务的原子性,经常会举银行的例子,现在我们也用银行的例子来说明一下事务原子性的问题,

现在银行卡常常是有多个用户的,比如大多数有一个理赔账户,活期存款账户,如果我们想从理赔账户中转出两千元

到银行存款账号,通常我们要进行以下几步操作

通常我们要进行以下几步操作,第一步是检查理财账号的余额是否高于2000,第二步是从理财账户中减去2000元,

第三步从活期存款账户上增加2000元,以上的三个步骤要作为一个整体一起来完成,要是我们执行到第二步系统

就奔溃了,如果没有事务原子性,会发生什么呢,毫无疑问,我们就会损失2000元,相信这是所有用户都不能接受的,

如果以上三个步骤都在一个事务中,当执行到第二步系统奔溃了,在系统恢复后就会发现有没有提交的事务,这个时候

就会对操作的事务回滚

这样就避免了用户的损失,所以事务的首先的一个特性呢,要具有原子性,保证事务的处理过程中要么

全部完成,要么就全部回滚失败

事务的第二个特性就是事务的一致性,其定义是这样的,一致性就是事务将数据库从一种一致性状态转换到

另外一种一致性状态,在事务的开始之前和事务的结束之后,数据库的完整性不应该被破坏,概念总是很难以理解,

我们还是以上面的银行转账的例子来说,就是在转账之前和转账之后,我们账户的总金额不应该有任何的变化,转账

之前在我们的银行账号中,转账之后余额到活期账户中,但是账户总金额是不应该有任何变化的,这个看似是理所当然

的事情了,但是在数据库的文件系统中呢,这一步是很难做到的

那我们接下来看看事务的第三个特性,事务的隔离性,所谓的隔离性呢,就是要求一个事务对数据库的数据,进行修改,

在未提交完成之前,对于其他事务是不可见的,同样的我们还是以上面的存款例子来说吧,当我们执行完第二步,在理财账户

中减去2000元之后,如果这个时候另外一个事务,需要对所有理财账号的余额呢,进行汇总,这个时候事务还能够在我们的理财

账户中看到我们理财账号的两千块钱,这是由于我们第一个事务减去两千块钱,加上事务还没有提交,所以对于第二个事务来说呢,

应该是不可见的,这就是事务的隔离性,在SQL的标准中呢,定义了四种隔离性

下面我们依次来看一下隔离性都有哪些,首先第一种隔离性呢,就是未提交读,所谓的未提交读呢,

就是在未提交读的事务隔离级别中,事务对数据进行了修改,即使事务还没有被提交,所以其他事务也是

可见的,事务可以读取未提交的数据,也就是被称之为脏读,未提交的数据我们也称之为脏数据,之前我在

使用SQL Server时,经常会建议,在进行查询的时候,在老板的SQL中呢,支持非锁定读的,所以也是一种没有

办法的事情,当然在新的SQL中呢,有办法实现SQL的读了,所以在通常的情况下,是不建议使用脏读隔离级别的,

因为可能会造成很多逻辑上的问题,隔离级别称之为已提交读,相信大家对于已提交读已经很熟悉了,因为这是大多数

数据库默认的隔离级别,比如ORACLE,SQL Server,他们隔离事务都是隔离读,MYSQL是一个例外,已提交读满足之前的

定义,一个事务开始时,只能看到已提交事务所做的更改,或者一个事务从开始到提交前,对数据所做的修改,与其他事务

来说是不可见的,这就是已提交读,那事务隔离级别第三个就是可重复读,该级别保证了在同一个事务中,读取的结果是

一致的,相比可重复读的隔离级别呢,可提交是不可重复读,那么这两个级别到底有什么区别呢,我们可以通过一个简单的例子

来演示一下,那现在就进入到演示的系统

首先我们可以有两个连接,我们在数据库中已经建立了这样一张表,你们可以先看一看,这张表很简单,就是

一张序列表

他具有这么几个数据,现在我们看一下这个事务的隔离级别是什么,大家可以看到这个事务隔离级别是可重复读

那么这个时候我们启动一个事务,begin;查询所有id小于7的数字

同时我们在第二个进程中,同样我们进入到这个数据库中,我们会看到这个表,在这里同样启动一个事务,

这个时候我们对这个表t进行一个插入,我们插入2这个值,对这个事务进行提交

我们回到第一个连接,同样我们执行上面这个查询,同样看到的还是这三个数字,看不到已经提交的数字2,

如果我们把当前的事务级别给改一下,比如我们把当前的事务终止掉,设置一下我们的事务隔离级别

设置成读已提交,我们看一下刚才的会变成什么样子,现在我们已经把事务设置成读已提交,事务隔离级别已经读已提交了

同样我们进行刚才的实验,同样我们选出id小于7的,因为刚才已经插入了一个2,当然我们启动了事务当然是可以

看到2的

同样我们在连接2中,再插入另外一个数字,咱们再看一下,比如再启动一个事务,我们可以插入4,这个是在表里

没有的,插入一个4,提交这个事务

那么我们回到第一个连接,同样查询id小于7的数字,那我们就可以看到id为4的数字了

但是这个事务我们还没有给提交,所以在读已提交的情况下呢,我们是不可重复读的,因为在同一事务中,

我们两个执行相同的SQL,结果是不一样的,而在可重复读中,虽然同样提交了一个事务,但是我们同时注册了

一个结果呢,是一致的,称之为可重复读,这就是可重复读和已提交读的差别,来看看第四个隔离级别,第四个

隔离级别就是串行化,串行化是最高的隔离级别,简单来说呢,串行化是在读取的每一行数据上都加锁,所以

可能导致大量的锁超时和锁占用问题,所以我们在实际业务中呢,我们很少使用这个隔离级别,除非要求严格

数据一致性,并且是在可以接收并发前提下,我们才会考虑使用这种隔离级别,从上面的介绍我们不难看出,

对于系统隔离级别,从隔离性来说,分别是未提交读,已提交读,可重复读,和可串行化读,而并发性来说呢,

跟隔离性来说正好是相反的,并发性的由高到低排列呢,应该是未提交读的并发性是最高的,可串行化的并发性

是最低的,大家在我们正常的实际工作中呢,选择不同的隔离级别,而对于InnoDB来说呢,默认的隔离级别呢是

可重复读,而不是读已提交

来看事务的最后一个特性,也就是持久性,一旦事务提交,就永久的保存在数据库中,此时即使系统奔溃,

已提交的修改也不会被丢失,这里说的持久性是相对来说的,只能从数据库的角度来说,事务的持久性,

而不包括一些外部因素,如磁盘损坏情况,就不是这里事务的持久性的问题,要真正保证在磁盘损坏的情况下,

不丢失数据的话,那么只有靠数据的备份,或者DB的复制高可用的架构,才能做得到,那么了解了事务之后呢


来看看什么是大事务,就是运行时间比较长,操作数据比较多的事务,举个例子来说,相信大家都接触过

余额宝这样的理财产品,这种产品的一个特点呢,就是每天都会计算用户前一天的理财收入所得,而如果我们

在一个事务中,所有的理财事务都进行计算,并更新到用户的余额中,这数以亿计的用户的更新可能要几个小时,

而且一旦中间出现任何的问题,会进行回滚,事务所需要的时间就更加的不可估量,更新的过程中会对相关的用户

进行加锁,造成用户不能使用余额相关的问题,像这样的事务就称之为大事务,当余额宝的计算和更新,并不是在

一个事务中来完成了,所以我们也没有遇到像上面的这种情况,但是从上面的例子中,我们不难看出,大事务的影响

主要有以下几个,首先第一个是锁定太多的数据,造成大量的阻塞和锁超时,对于InnoDB的这种事务引擎来说,虽然

使用的是行级锁,但是在一个事务中,为了保证事务的一致性,通常会讲所有相关的应用都会加锁,如果我们涉及到的

数据比较多,比如下面的例子中几乎会涉及到所有用户记录,这样就会把所有的记录全部锁住,如果有用户要使用余额宝

支付,这个时候就会产生阻塞,在并发比较大的情况下呢,直接使用数据库的服务器呢,被大量的连接所占满,同时会严重的

影响数据库的性能和稳定性,而大事务给我们带来的第二个风险呢,回滚所需要的时间比较长,并且在回滚中,所有对锁定的

数据仍然被锁定,那可能回滚所需的时间可能比我们之前的事务花的时间还要长,大事务给我们带来的第三个就是,容易造成

主从延迟,从MYSQL主从复制来看,只有在主服务器执行完之后,把日志写入到log中,这个时候从服务器才能通过log进行同步,

大家可以想一下,如果主上的事务执行了几个小时后再提交,并写入bin.log,是不是主从之间会延迟几个小时呢,以上就是

大事务给我们带来的几个大的问题,当然实际上还远远不止这些,不过这几个风险是比较重要的而已,那么我们要怎么处理

大事务呢

看看如何大事务进行处理,首先避免一次性处理太多的数据,对于一次要处理几百上千的操作呢,

我们可以采取分批处理的方法,就比如操作是增删改查这样的操作,比如上面的例子中,每天处理的用户

理财收入的例子,我们可以分成1万用户一批,处理完一批之后再处理另一批,这样就大大减少事务的大小,

避免了上面的种种问题,要把不必要的事务移出,在平时的工作中啊,多数是使用了查询的这种操作,而这些

查询操作呢,本身是可以不在事务中完成的,对于这种情况呢,要把查询从事务中移出去,保证事务中只有必要的

写操作,如果可以做到以下两点呢,我们就可以基本上避免了大事务的产生了

直观的展示了数据库在繁忙时的系统状态,并且简单了解了对性能有影响的一些因素,比如大表大事务等等,

接下来会详细分析对性能影响的因素,如果对MYSQL进行优化,希望听完完整的内容之后呢,可以完成对MYSQL

的性能优化,成为其中的高手

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值