Loading... 这篇文章将会总结mysql中事务的概念,并不涉及到相关的实际操作,实际操作将会另外总结为一篇文章。 在本博客中,”mysql”是一个系列文章,这些文章主要对mysql/mariadb的常用知识点进行了总结,每一篇博客总结的知识点有所不同,具体内容可参考mysql文章列表。 mysql文章列表直达链接:<a href="https://www.zsythink.net/archives/tag/mysql/" target="_blank" rel="noopener">mysql知识点总结</a> <img class=" ls-is-cached lazyloaded" title="1480776820928760.jpg" src="https://www.zsythink.net/wp-content/uploads/ueditor/php/upload/image/20161203/1480776820928760.jpg" alt="mysql.jpg" data-src="https://www.zsythink.net/wp-content/uploads/ueditor/php/upload/image/20161203/1480776820928760.jpg" style=""> <h2 id="wznav_0">事务概述</h2> 我们可以把事务理解成一组sql语句的集合,这样描述可能不太容易理解,不要着急,我们先大概的描述一下理论,然后再进行形象的举例。 事务可以只包含一条sql语句,也可以包含多条复杂的sql语句,事务中的所有sql语句被当做一个操作单元,换句话说,事务中的sql语句要么都执行成功,要么全部执行失败,事务内的sql语句被当做一个整体,被当做一个原子进行操作。 mysql中,innodb存储引擎是支持事务的,而且innodb存储引擎的事务完全符合ACID的特性,ACID是如下四大特性的首字母缩写。 A:atomicity 原子性 C:consistency 一致性 I:isolation 隔离性 D:durability 持久性 原子性:整个事务中的所有操作要么全部执行成功,要么全部执行失败后混滚到最初状态。 一致性:数据库总是从一个一致性状态转为另一个一致性状态。 隔离性:一个事务在提交之前所做出的的操作是否能为其他事务可见,由于不同的场景需求不同,所以针对隔离性来说,有不同的隔离级别。 持久性:事务一旦提交,事务所做出的修改将会永久保存,此时即使数据库崩溃,修改的数据也不会丢失。 上述特性是ACID的理论基础,而innodb存储引擎的事务又符合ACID的特性,那么,我们来举个栗子,以方便我们理解。 首先我们来描述一个场景,在学习事务时一般都会使用这个场景作为举例,这个场景就是”转账”。 “天朝银行”有很多用户,目前,A用户账户上的余额为8000元,B用户账上的余额为5000元,现在A用户要向B用户转账1000元。 那么,当转账结束以后,A用户账户上的余额应该为7000元,B账户上的余额应该为6000元。 那么上述过程在数据库中应该转换为如下操作。 操作1:修改A用户账户对应的余额记录,8000-1000 操作2:修改B用户账户对应的余额记录,5000+1000 上述操作好像没毛病,但是假设,如果数据库刚刚完成操作1,好巧不巧,这个时候停电了,过了两分钟,又来电了,当我们再次查看数据库时,发现A用户余额为7000,比停电之前少了1000,发现B用户的账户余额仍然为5000,与停电之前一样,出现这种情况是因为数据库只完成了操作1,而没来得及完成操作2,那么,1000块大洋凭空消失了,所以,我们应该防止这样的悲剧发生,没错,解决方法就是使用事务。 我们之前说过,事务中的所有sql语句都被当做一个整体,要么全部执行成功,要么在其中某些操作执行失败后回滚,回滚到最初的状态,就好像什么都没有发生过一样。那么利用事务的这个特性,就可以解决之前的问题,我们可以把转账的sql语句写入到事务中,如下。 事务开始 update A用户余额 – 1000 update B用户余额 + 1000 提交事务(事务结束) 利用事务完成上述操作,即使数据库刚刚将A用户账户余额减去1000时停电了,由于事务的特性,当再次使用数据库时,也不会出现A用户余额变为7000,B用户余额仍然为5000的情况,为什么呢?事务是怎样实现这样的功能的呢?你一定想到了这些问题,答案就是,事务是通过”事务日志”来实现这种功能的。 “事务日志”可以细分为 redo log 和 undo log,我们一个一个聊。 <h2 id="wznav_1">redo log概述</h2> 先说redo log,mysql会将事务中的sql语句涉及到的所有数据操作先记录到redo log中,然后再将操作从redo log中同步到对应数据文件中(此处假设事物操作的数据量并非巨大),换句话说,在事务执行提交成功以前,在修改对应的数据文件中的记录之前,一定要保证对应的所有修改操作已经记录到了redo log中,假设事务中的sql语句涉及到60条记录的修改,那么在修改这60条记录之前,要将这60条修改操作记录到redo log中,当这60条操作都记录到redolog中以后,再从redo log中一条一条同步到数据文件的对应记录中。所以,即使数据文件中的数据被修改到一半时被打断(比如停电),那么也能依靠redo log中的日志将剩余的部分操作再次同步到对应的数据文件中。 使用redo log,能够实现ACID中的A,也就是原子性,即事务中的所有sql被当做一个执行单元。 redo log其实由两部分组成:redo log buffer(重做日志缓冲) 和 redo log file(重做日志文件) redo log buffer存在于内存之中,是易失的,redo log file是持久的,存在于磁盘上。 <img class=" lazyloaded" src="https://www.zsythink.net/wp-content/uploads/2017/02/022117_0825_1.png" alt="" data-src="https://www.zsythink.net/wp-content/uploads/2017/02/022117_0825_1.png" style=""> 重做日志先被写入到redo log buffer中,虽然内存的速度极快,但是无法满足持久性的需求,因为内存中的数据是易失的,所以为了满足持久性,需要将redo log buffer中的日志写入到redo log file中,相当于从内存中同步到磁盘上,所以磁盘的性能会影响事务的性能,由于redo log file是磁盘上一段连续的空间,所以写速度还是比较快的,比离散的写操作要快很多,当操作记录被记录到redo log file中以后,再从redo log file中将操作同步到数据文件中。 虽然,我们应该实时将redo log buffer中的数据写入到redo log file中以保证数据的安全性,但是这样会极大的降低性能,我们可以通过设置innodb_flush_log_at_trx_commit参数来修改从redo log buffer写入redo log file的策略,但是如果这样做,则会丧失持久性,有可能会丢失部分数据,具体使用怎样的刷写策略,还需要根据实际情况自己权衡。 redo log是物理日志,之所以说它是物理日志,是因为redo log 中记录的是数据库对页的操作,而不是逻辑上的增删改查,重做日志具有幂等性。 redo log先说到这里,一会儿再回过头来聊redo log。 <h2 id="wznav_2">undo log概述</h2> 刚才我们大致的描述了什么是redo log ,现在来聊聊什么是undo log,我们可以把undo log理解成数据被修改前的备份。如果说事务进行了一半,有一条sql没有执行成功,那么数据库可以根据undo log进行撤销,将所有修改过的数据从逻辑上恢复到修改之前的样子,注意,是逻辑上还原成原来的样子,比如,之前insert了1000条数据 ,那么就delete它们,如果delete了2000条,就insert它们,如果update了500条数据,就再次根据undo log去update它们,所以,undo log是逻辑日志,与redo log记录的页操作物理日志不同。 <h2 id="wznav_3">log group概述</h2> log group为重做日志组,一个重做日志组(log group)中有多个重做日志文件(redo log file),当日志组中的第一个logfile被写满,则会开始将redo log写入日志组中的下一个重做日志文件中,以此类推,当日志组中的所有redo log file都被写满,则将redo log再写入第一个redo log file 中,覆盖原来的redo log,以便新的redo log 被写入。 如果重做日志所在的设备崩溃了,那么redo log将有可能丢失,这样就无法保证redo log在任何时候都是可用的,所以,log group还支持日志组镜像,为了保险起见,我们应该将log group放在有冗余能力的设备上,比如raid1。 <h2 id="wznav_4">其他</h2> redo log存储于重做日志文件中,undo log则不同,undo存放在数据库内部的特哥特殊段中,这个段被称为undo段(undo segment),undo段位于共享表空间中。 mysql中,innodb存储引擎是支持事务的,myisam存储引擎是不支持事务的,不管是redo log或者undo log,都是innodb的产物,或者说是innodb存储引擎层面的产物,而在mysql中,还有另外一种重要的日志,二进制日志,也就是平常所说的binlog,它是建立mysql主从复制环境时所必须的日志,但是binlog并不是innodb存储引擎层面的产物,而是整个mysql数据库层面的产物,换句话说,binlog不止针对于innodb,mysql数据库中的任何存储引擎对于数据库的更改都会产生二进制日志(binlog)。 innodb的redo log记录的是物理格式的日志,记录了对页的操作,而binlog记录的是逻辑日志,记录的是对应的SQL。 redolog与binlog写入磁盘的时机也不同,innodb的redo log在事务进行时会不断的写入redo log file,binlog只在事务提交完成后进行一次磁盘写入。 其实,不管是redo log 还是 undo log,都可以理解成恢复数据库的手段。 如果上述总结有误,请不吝赐教,如果这篇文章对你有帮助,可以免费点赞哦 ^_^···· 转载自朱双印日志https://www.zsythink.net/archives/1204 Last modification:May 29, 2024 © Allow specification reprint Like 如果觉得我的文章对你有用,请随意赞赏