深入理解事务与锁机制

北京哪里治疗白癜风安全 http://disease.39.net/yldt/bjzkbdfyy/

一、事务及其特性

首先看看什么是事务?事务具有哪些特性?关于事务,上大学的时候,你应该有接触过相关的课程。简单来说,事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全做,要么全不做,是一个不可分割的工作单元。

一个逻辑工作单元要成为事务,在关系型数据库管理系统中,必须满足4个特性,即所谓的ACID:原子性、一致性、隔离性和持久性。

一致性:事务完成之后,事务所做的修改进行持久化保存,不会丢失。

原子性:事务的所有操作,要么全部完成,要么全部不完成,不会结束在某个中间环节。

持久性:事务开始之前和事务结束之后,数据库的完整性限制未被破坏。

隔离性:当多个事务并发访问数据库中的同一数据时,所表现出来的相互关系。

ACID及它们之间的关系如下图所示,比如4个特性中有3个与WAL有关系,都需要通过Redo、Undo日志来保证等。

1.一致性

首先来看一致性,一致性其实包括两部分内容,分别是约束一致性和数据一致性。约束一致性:数据库中创建表结构时所指定的外键、Check、唯一索引等约束。可惜在MySQL中,是不支持Check的,只支持另外两种,所以约束一致性就非常容易理解了。数据一致性:是一个综合性的规定,或者说是一个把握全局的规定。因为它是由原子性、持久性、隔离性共同保证的结果,而不是单单依赖于某一种技术。

2.原子性

接下来看原子性,原子性就是前面提到的两个“要么”,即要么改了,要么没改。也就是说用户感受不到一个正在改的状态。MySQL是通过WAL(WriteAheadLog)技术来实现这种效果的。

举例来讲,如果事务提交了,那改了的数据就生效了,如果此时BufferPool的脏页没有刷盘,需要使用Redo日志恢复出来的数据。而如果事务没有提交,且BufferPool的脏页被刷盘了,需要通过Undo来实现了,Undo又是通过Redo来保证的,所以最终原子性的保证还是靠Redo的WAL机制实现的。

3.持久性

所谓持久性,就是指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,接下来的操作或故障不应该对其有任何影响。前面已经讲到,事务的原子性可以保证一个事务要么全执行,要么全不执行的特性,这可以从逻辑上保证用户看不到中间的状态。一旦事务提交,通过原子性,即便是遇到宕机,也可以从逻辑上将数据找回来后再次写入物理存储空间,这样就从逻辑和物理两个方面保证了数据不会丢失,即保证了数据库的持久性。

4.隔离性

所谓隔离性,指的是一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对其他的并发事务是隔离的。锁和多版本控制就符合隔离性。

二、并发事务控制

1.单版本控制-锁

先来看锁,锁用独占的方式来保证在只有一个版本的情况下事务之间相互隔离,所以锁可以理解为单版本控制。

在MySQL事务中,锁的实现与隔离级别有关系,在RR(RepeatableRead)隔离级别下,MySQL为了解决幻读的问题,以牺牲并行度为代价,通过Gap锁来防止数据的写入,而这种锁,因为其并行度不够,冲突很多,经常会引起死锁。现在流行的Row模式可以避免很多冲突甚至死锁问题,所以推荐默认使用Row+RC(ReadCommitted)模式的隔离级别,可以很大程度上提高数据库的读写并行度。

2.多版本控制-MVCC

多版本控制也叫作MVCC,是指在数据库中,为了实现高并发的数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能看到自己应该看到的数据版本。

每一次对数据库的修改,都会在Undo日志中记录当前修改记录的事务号及修改前数据状态的存储地址(即ROLL_PTR),以便在必要的时候可以回滚到老的数据版本。例如,一个读事务查询到当前记录,而最新的事务还未提交,根据原子性,读事务看不到最新数据,但可以去回滚段中找到老版本的数据,这样就生成了多个版本。

多版本控制很巧妙地将稀缺资源的独占互斥转换为并发,大大提高了数据库的吞吐量及读写性能。

三、特性背后的技术原理

1.原子性背后的技术

每一个写事务,都会修改BufferPool,从而产生相应的Redo日志,这些日志信息会被记录到ib_logfiles文件中。因为Redo日志是遵循WriteAheadLog的方式写的,所以事务是顺序被记录的。

在MySQL中,任何BufferPool中的页被刷到磁盘之前,都会先写入到日志文件中,这样做有两方面的保证。如果BufferPool中的这个页没有刷成功,此时数据库挂了,那在数据库再次启动之后,可以通过Redo日志将其恢复出来,以保证脏页写下去的数据不会丢失,所以必须要保证Redo先写。

因为BufferPool的空间是有限的,要载入新页时,需要从LRU链表中淘汰一些页,而这些页必须要刷盘之后,才可以重新使用,那这时的刷盘,就需要保证对应的LSN的日志也要提前写到ib_logfiles中,如果没有写的话,恰巧这个事务又没有提交,数据库挂了,在数据库启动之后,这个事务就没法回滚了。所以如果不写日志的话,这些数据对应的回滚日志可能就不存在,导致未提交的事务回滚不了,从而不能保证原子性,所以原子性就是通过WAL来保证的。

2.持久性背后的技术

一个“提交”动作触发的操作有:binlog落地、发送binlog、存储引擎提交、flush_logs,check_point、事务提交标记等。这些都是数据库保证其数据完整性、持久性的手段。

通过原子性可以保证逻辑上的持久性,通过存储引擎的数据刷盘可以保证物理上的持久性。这个过程与前面提到的Redo日志、事务状态、数据库恢复、参数innodb_flush_log_at_trx_


转载请注明:http://www.aierlanlan.com/rzgz/5695.html