1.Redo log   

什么是redo log  redo log也叫重做日志,用来实现事务的持久性。当事务提交之后会把所有修改信息存放在改日志中。mysql为了提升性能不会把每次的修改同步到磁盘中,而是先存到Buffer Pool中,把这个当做缓存来用,然后使用后台的线程去缓冲池和磁盘之前的同步。

如果在写入Buffer Pool中后,突然断电或者宕机,还没来得及进行同步,这样会导致丢失已经提交事务的修改信息。所以引入了redo log来记录已经提交事务的修改信息,并且会把redo log持久化到磁盘,系统重启之后会再读取redo log回复最新数据。

2.Undo log

undo log在回滚日志,用于记录数据被修改前的信息。他正好跟前面所说的重做日志记录相反。undo log记录修改前的数据,为了在发送错误回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。undo记录了事务修改之前版本的信息,假设由于系统错误或者rollback操作而回滚的话可以根据undo log的信息进行回滚到被修改前的状态。

MySQL的锁技术

当同一个时刻有多个请求来修改表中数据的时候,需要一种措施来进行并发控制,不然很可能会造成不一致。

通过读、写锁两种锁来对读写请求进行处理。

MVCC 多版本并发控制

InnoDB的MVVC,是通过在每行记录里面保存三列隐藏列来实现的。记录隐式ID、事务ID和回滚指针(指向undo log的记录)

MVCC在mysql中实现的依赖的是undo log与read view

undo log:  用来记录某行数据的多个版本。

read view: 用来判断当前版本的可见性。

版本链的机制: readView 

生成ReadView的时机不同, READ COMMITTD在每一次进行普通SELECT操作前都会生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个。

1.用一个单链表的结构存放每个事务对应的行的数据,通过事务id可以获取对应的数据。

2.配合readview的活跃事务组,可以判断当前应该读哪个节点的数据。如果当前事务不在版本链上就像前读取节点,知道节点的事务版本号不在活跃事务组,那么这个版本的数据就是最新已经提交数据。

版本链,readview的使用场景

【创建事务节点】当我创建一个新的事务需要读取一个数据时候。需要去查询活跃事务列表,假设当前我的事务id是200,当前活跃的事务id没有是200的。需要去拷贝一个最新的不活跃事务并将版本链最后插入一个新节点200.mysql会去对比版本链和readview,假设版本链的数据为[1,50,100,150],活跃列表为[100,150].所以事务200拷贝事务50并插入版本链最后,且将200加入活跃链表最后一个元素。

【使用事务节点】当我们再次使用事务200查询或者修改数据,需要读版本链上的数据,因为上次操作已经咋版本链上做了200号节点。因此次吃事务读到的都是200号节点的数据,这样就隔离了其他为未提交的事务,全部的增删改查都在200号版本上进行。

【readview实现事务隔离级别】以上两点都是基于隔离级别:读已提交来进行的。当mysql设置为可重复读的时候,不同事务任然要保存在版本链的不同节点上。只不过新的事务创建的时候拷贝了当下的readview列表,只要当前事务不提交。 就一直使用这个拷贝的活跃列表。假设此时事务100已经提交,我们在新事务下执行了select ,查询到的活跃列表100还是未提交,读取的还是50号事务提交的记录。

事务的实现:

  事务的原子性是通过undo log来实现的。

  事务的持久性是通过redo log来现实的。

  事务的隔离性是通过(读写锁+MVCC)来实现的

  而事务的终极大boss一致性是通过原子性,一致性,隔离性来实现的。

03-28 11:36