zoukankan      html  css  js  c++  java
  • mysql事物原理(一)-undo log、redo log、MVCC

    redo log

    redo log叫做重做日志.用于解决数据库事物提交 还未刷入磁盘,服务器down机导致的数据丢失的问题。

    InnoDB作为MySQL的存储引擎,数据存储在磁盘中,如果每次读写数据都要操作磁盘IO效率会很低,为此InnoDB提供了缓存(Buffer Pool),Buffer Pool中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(刷脏)

    Buffer Pool的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。

    于是,redo log被引入来解决这个问题:当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。

    既然redo log也需要在事务提交时将日志写入磁盘,为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:

    (1)刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。

    (2)刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。

    undo log

    undo log的2个主要作用是实现MVCC和事物回滚

    当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,当 update 一条记录时,它记录一条对应相反的 update 记录,如果 update 的是主键,则是对先删除后插入的两个事件的反向逻辑操作的记录。

     在事物回滚时就会反向读取相应内容进行回滚,也可以根据undo log读取到被修改后数据的原值

    MVCC的实现原理

    MVCC的实现主要利用到了数据库隐式字段和undo log、ReadView

    MVCC的好处主要实现思想是通过数据多版本来做到读写分离。从而实现不加锁读进而做到读写并行。

    MVCC结构

    Column1 Column2位数据格式

    DB_TRX_ID(隐式字段) 最近一次修改的事物id(注:事物id都是递增的)

    DB_ROLL_PTR(隐式字段)  回滚日志 指向undo log

    DB_ROW_ID(隐式字段) 自增ID如果数据库表没有指定主键 则默认以此作为聚簇索引

    undo log 版本链

    事物A id=1的事物将小明改为小张

    事物B id=2的事物将age改为30

    ReadView

    read view(快照)是基于undo log实现的可以实现不加锁的情况下并发读 读已提交和可重复读都是通过ReadView实现

    快照读和当前读

    详情可可以看《快照读和当前读》

    数据结构

    m_ids:当前有哪些事务正在执行,且还没有提交,这些事务的 id 就会存在这里

    min_trx_id:是指 m_ids 里最小的值

    max_trx_id:下一个要生成的事物id,因为事物id是递增的 肯定比当前所有事物id要大

    creator_trx_id: 创建read view的事物id

    RE隔离级别读已提交实现原理

    图1.事物A id等于1将数据修改并提交

    图2.事物B执行查询

     

    1.事物B执行快照读(注:RR隔离级别只会生成一次快照 RE隔离级别每次都会生成新的快照

    2.读取到数据通过数据隐藏列DB_TRX_ID值1跟min_trx_id做比较, DB_TRX_ID<min_trx_id 说明最近修改此数据的事物已经提交则可以正常读取 column1=小张   column2=32

    图3

    1.事物C将colunm2=32 改为16事物并未提交

    2.事物B执行select读取数据通过DB_TRX_ID与min_trx_id做比较 发现比最小事物id大。表示有可能读到的。再将DB_TRX_ID=4在min_ids进行查找 成功找到。发现事物还未提交

    3.通过undolog链跟往上找(通步骤2一样的查找方式)成功查到 colunm1=小明 colunm2=32的数据 成功读取  

    图4

    1.又回到了图一。事物C提交事物后。事物B进行查询重新生成快照(RE隔离级别每次都会生成新的快照) 

    2.这个时候m_ids里面已经没有4了。数据行DB_TRX_ID>min_trx_id 同时又不在m_ids里面存在表示已经提交了直接读取

    RR可重复读实现原理

    流程都一样 唯一不同的是只会生成一次快照,就算事物C提交了  m_ids[2,4] 还是有2和4 所以读到的数据还是小明 32

  • 相关阅读:
    SIFT算法详解(转)
    相似图片搜索的原理(二)(转)
    相似图片搜索的原理(转)
    几种常见模式识别算法整理和总结(转)
    Android客户端与服务端交互之登陆示例
    Android中SQLite使用
    音视频转码后合成的一些例子
    Android MediaCodec 使用例子
    (转)H264(NAL简介与I帧判断)
    Android Camera 使用一例,视频聊天app
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15129211.html
Copyright © 2011-2022 走看看