mysql事务、日志、MVCC讲解

mysql事务和日志讲解

    • 事务
    • 日志
      • binlog、relaylog(主从复制)
      • redolog(两阶段提交)
        • 两段提交
      • MVCC (多版本并发控制)
        • mysql 存在的并发场景
        • MVCC的组成
          • 案例分析
          • 可见性算法
          • 幻读

本文讲解的是mysql的事务和日志之间的关联,并有部分MVCC的讲解。有和理解错的话请指正。

事务

事务的特性(ACID):
mysql事务、日志、MVCC讲解_第1张图片

  • 原子性(A):在同一个事务中存在的n多条sql语句,要么全部成功,要么全部失败。如果有部分sql失败了,则所有sql结果通过undolog回滚日志来恢复初始状态
  • 一致性(C):事务执行之前和执行之后数据库均处于一致性状态。它是由 原子性、隔离性、持久性来实现的
  • 隔离性(I):多个事务操作同一张表的时候,每个事务互不干扰。锁、MVCC多版本并发控制来实现 数据安全问题用RR
  • 持久性(D):当事务被提交以后数据库中的数据就会被写入到磁盘中,数据改变就是永久性的了。通过redolog来实现

日志

mysql事务、日志、MVCC讲解_第2张图片

日志类型:

  • undolog:回滚日志 原子性和MVCC的支撑
  • redolog:前滚日志 将数据持久化
  • binlog: 主从复制
  • relaylog:中继日志 在进行主从复制时 从机里先存储的日志
  • slowlog:慢查询日志 超过指定时长的sql语句
  • errorlog:错误日志

    undolog、redolog归属于Innodb 存储引擎
    binlog、relaylog、slowlog、errorlog归属于 mysqlserver

binlog、relaylog(主从复制)

mysql事务、日志、MVCC讲解_第3张图片

  • 多线程进行操作master数据库,将数据存放到数据库中,并生成binlog记录,主从数据库要保证数据的同步一致性,主从直接会由IO Thread线程读取 master的binlog同步到slave内,并生成relaylog,然后由SQL Thread线程回放数据,保证主从两个数据库数据一致

redolog(两阶段提交)

  • redolog 是顺序读写机制,数据库数据属于随机读写机制,因为顺序读写效率远高于随机读写,所以操作数据库时,先将数据存到redolog中记录,然后再从redolog中放到数据库磁盘中(采用了WAL技术)。如果写到数据库的时候断电或宕机之类的,恢复后会从redolog中继续同步;如果写到redolog时出现断电或宕机则数据丢失。
    WAL:write ahead log 预写日志
两段提交

mysql事务、日志、MVCC讲解_第4张图片

  • 为了保证redolog和binlog的数据同步一致性,则采用了两段提交的方式。
    数据想写入redolog中其状态为perpare状态(此状态的数据不能进行恢复),然后将数据写到binlog中,最后将redolog的数据提交。 如果再步骤1出现问题,在服务器恢复后检测到redolog有perpare状态的数据,则去binlog中找对应的数据,若未找到则删除redolog的此数据记录,在binlog中找到了,则将redolog中此数据commit;如果步骤2出现问题,先检测redolog记录,然后再去binlog中找对应的,找到commit,未找到删除。

MVCC (多版本并发控制)

MVCC 被称为多版本并发控制,它是为了提高数据库并发性能,以不加锁的方式来解决读写操作并发问题。
场景1
mysql事务、日志、MVCC讲解_第5张图片
场景2
mysql事务、日志、MVCC讲解_第6张图片

  • 当前读:读取当前的数据,即最新的数据(update、delete、insert、select…for update、select … lock in share mode可触发)
  • 快照读:读取历史数据(select 可触发)
mysql 存在的并发场景
  • 读读 不存在数据安全问题
  • 读写 脏读、幻读、不可重复读(MVCC解决的问题)
  • 写写 更新丢失
MVCC的组成
  • 隐藏字段 数据库的表在定义的时候除了我们自己声明的字段之外,还会有其他隐藏的字段

    • DB_TRX_ID 最近事务的id。创建这条记录或者最新更改这条数据的事务id
    • DB_ROLL_PRT 回滚指针,指向了记录上一个版本
    • DB_ROW_ID 隐藏主键,如果表没有主键,则会生成一个6字节的rowid
  • undolog 在进行 insert、delete、update操作时生成的方便回滚到历史数据的日志
    mysql事务、日志、MVCC讲解_第7张图片
    因此undolog会形成一个链表,链首是最新的旧记录,链尾是最旧的旧记录,
    当undolog的日志记录达到一定值时,后台有一个purge线程进行删除操作

  • readview 读视图,在事务进行快照读的时候产生的读视图,保存的并不是实际的数据,而是事务的相关信息。

    • trx_list 当前系统活跃的事务id列表
    • up_limit_id 活跃列表中事务id最小的值
    • low_limit_id 系统尚未分配的下一个事务id
案例分析
  • 案例1图案:
    mysql事务、日志、MVCC讲解_第8张图片
    readview视图字段对照
    mysql事务、日志、MVCC讲解_第9张图片

  • 案例二图案:
    mysql事务、日志、MVCC讲解_第10张图片
    readview视图字段对照
    mysql事务、日志、MVCC讲解_第11张图片

经过两次案例结果发现,readview值是一样的,可见性算法也是一样的,但是最后的结果不一致,可以猜测案例二的蓝色的readview和橙色的readview是否是一样的?
mysql事务、日志、MVCC讲解_第12张图片

根据可见性算法判断后发现和案例二的结果一致,因此可以确定猜测是对的。

因此可以得出一个结论:
第一次查询的时候生成了readview,第二次查询的时候沿用了第一次的readview

注意:由此可以关联到隔离级别
(RC:不可重复读 RR:幻读)
1、如果是RC(读后提交)隔离级别,那么每次进行快照读的时候都会产生新的readview
2、如果是RR(可重复读)隔离级别,那么只有在当前事务进行第一次快照读的时候产生readview,之后的都是沿用第一次的readview
可见性算法
	1、首先比较DB_TRX_ID < up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于进入下一个判断
	2、然后判断DB_TRX_ID >= low_limit_id,如果大于等于则表示DB_TRX_ID 所在的记录在readview生成后才出现,那么对于当前事务不可见,如果小于进去下一个判断
	3、然后判断DB_TRX_ID是否在活跃事务中,如果在 则表示在readview生成时刻,这个事务还在活跃状态,还没有commit,修改的数据当前事务也看不到;如果不在,则说明这个事务在readview生成之前就开始commit,那么修改的结果是可见的
幻读

其根本原因是:当前读和快照读一起使用,如果同一个事务中只有快照读则不会出现幻读问题。
MVCC解决不了幻读问题,幻读是加锁解决的
比如:select * from table for update;

你可能感兴趣的:(数据库,mysql,数据库)